From 9b086e60795efd6e9d674adb9d933ff1eb64502f Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sat, 3 Oct 2026 10:34:31 +0200 Subject: [PATCH 001/220] Validate Exchange Graphs From One Parsed Document Parse each Bundle's JSON once and share the parsed document across every validation pass instead of re-encoding resources per pass; drain Foundation temporaries per graph. Move the plain-decimal formatter into String+Utils with a Foundation-free `isBlank`, and nest `ApplicationDeviceError` as `ApplicationDevice.InitError`. Co-Authored-By: Claude Fable 5.1 --- .../GroveFHIRContract/ApplicationDevice.swift | 26 +-- .../ExchangeGraph+EntryIdentity.swift | 48 ++--- .../ExchangeGraph+EventPolicy.swift | 57 +++--- .../ExchangeGraph+Profiles.swift | 25 ++- .../ExchangeGraph+References.swift | 16 +- .../ExchangeGraph+SerializedPolicy.swift | 8 +- .../ExchangeGraph+StudyContext.swift | 21 ++- .../ExchangeGraph+SupportIdentity.swift | 24 ++- .../ExchangeGraph+ValidationDocument.swift | 118 ++++++++++++ Sources/GroveFHIRContract/ExchangeGraph.swift | 96 +++++++--- .../GroveFHIRContract/ExchangeIdentity.swift | 45 +---- ...+PlainDecimal.swift => String+Utils.swift} | 21 +++ ...ExchangeGraphValidationDocumentTests.swift | 171 ++++++++++++++++++ .../HealthKitApplicationIdentityTests.swift | 8 +- 14 files changed, 511 insertions(+), 173 deletions(-) create mode 100644 Sources/GroveFHIRContract/ExchangeGraph+ValidationDocument.swift rename Sources/GroveFHIRContract/{String+PlainDecimal.swift => String+Utils.swift} (80%) create mode 100644 Tests/GroveHealthKitFHIRTests/ExchangeGraphValidationDocumentTests.swift diff --git a/Sources/GroveFHIRContract/ApplicationDevice.swift b/Sources/GroveFHIRContract/ApplicationDevice.swift index 01aa296ea..87cc32562 100644 --- a/Sources/GroveFHIRContract/ApplicationDevice.swift +++ b/Sources/GroveFHIRContract/ApplicationDevice.swift @@ -9,16 +9,15 @@ public import Foundation -public enum ApplicationDeviceError: Error, Equatable, Sendable { - case blankName - case invalidBundleIdentifier(String) - case blankVersion - case blankBuild -} - - /// The converting application, as the immutable application Device snapshot states it. public struct ApplicationDevice: Hashable, Sendable { + public enum InitError: Error, Equatable, Sendable { + case blankName + case invalidBundleIdentifier(String) + case blankVersion + case blankBuild + } + public let name: String public let bundleIdentifier: String /// The marketing version alone; the build that produced the resource is ``build``. @@ -36,7 +35,7 @@ public struct ApplicationDevice: Hashable, Sendable { bundleIdentifier: String, version: String, build: String? = nil - ) throws(ApplicationDeviceError) { + ) throws(InitError) { guard !name.isBlank else { throw .blankName } @@ -59,7 +58,7 @@ public struct ApplicationDevice: Hashable, Sendable { /// /// A host without a bundle identifier, such as a bare test runner, has no application identity /// to state and fails here rather than inside a conversion. - public init(bundle: Foundation.Bundle) throws(ApplicationDeviceError) { + public init(bundle: Foundation.Bundle) throws(InitError) { let info = bundle.infoDictionary ?? [:] let identifier = bundle.bundleIdentifier ?? "" try self.init( @@ -78,10 +77,3 @@ public struct ApplicationDevice: Hashable, Sendable { return value.utf8.allSatisfy { $0.isASCIIAlphaNumeric || $0 == 0x2D || $0 == 0x2E } } } - - -extension String { - var isBlank: Bool { - trimmingCharacters(in: .whitespacesAndNewlines).isEmpty - } -} diff --git a/Sources/GroveFHIRContract/ExchangeGraph+EntryIdentity.swift b/Sources/GroveFHIRContract/ExchangeGraph+EntryIdentity.swift index b7d4dfa1c..1d9da49ab 100644 --- a/Sources/GroveFHIRContract/ExchangeGraph+EntryIdentity.swift +++ b/Sources/GroveFHIRContract/ExchangeGraph+EntryIdentity.swift @@ -30,24 +30,26 @@ extension ExchangeGraph { /// Every Grove-typed resource Identifier carries one closed role, a canonical value, and a role no /// other Identifier of the resource repeats. - static func validateResourceIdentifiers(entries: [BundleEntry]) throws(ExchangeGraphError) { - for entry in entries { + static func validateResourceIdentifiers( + entries: [BundleEntry], + document: ValidationDocument + ) throws(ExchangeGraphError) { + for (entryIndex, entry) in entries.enumerated() { guard let resource = entry.resource else { continue } - let rawIdentifiers: [[String: Any]] + let decodedIdentifiers: [Result] do { - let object = try JSONSerialization.jsonObject(with: try JSONEncoder().encode(resource)) as? [String: Any] - rawIdentifiers = object?["identifier"] as? [[String: Any]] ?? [] + decodedIdentifiers = try document.resourceIdentifiers(at: entryIndex) } catch { throw .invalidEntries(String(reflecting: type(of: error))) } var roles: Set = [] - for (index, rawIdentifier) in rawIdentifiers.enumerated() { + for (index, decoded) in decodedIdentifiers.enumerated() { let location = "\(resource.resourceType).identifier[\(index)]" let identifier: Identifier do { - identifier = try JSONDecoder().decode(Identifier.self, from: try JSONSerialization.data(withJSONObject: rawIdentifier)) + identifier = try decoded.get() } catch { throw .invalidEntries(String(reflecting: type(of: error))) } @@ -78,11 +80,11 @@ extension ExchangeGraph { /// Every entry carries one complete key that is its resource's highest-priority typed identifier /// (or its entry-node key), no two entries share a key, and each fullUrl is the key's UUIDv5. - static func validateEntryKeys(entries: [BundleEntry]) throws(ExchangeGraphError) { + static func validateEntryKeys(entries: [BundleEntry], document: ValidationDocument) throws(ExchangeGraphError) { var keys: Set = [] var resourceTypesByFullURL: [String: String] = [:] for (index, entry) in entries.enumerated() { - let key = try entryKey(in: entry, index: index) + let key = try entryKey(in: entry, index: index, document: document) guard keys.insert(key.identifier).inserted else { throw diagnostic(.mobileExchangeDistinctEntryKey, location: "Bundle.entry[\(index)].extension.valueIdentifier") } @@ -92,11 +94,15 @@ extension ExchangeGraph { throw .ruleViolation(.mobileExchangeDeterministicFullUrl) } } - try validateLiteralReferences(in: entries, resourceTypesByFullURL: resourceTypesByFullURL) + try validateLiteralReferences(in: entries, document: document, resourceTypesByFullURL: resourceTypesByFullURL) } - private static func entryKey(in entry: BundleEntry, index: Int) throws(ExchangeGraphError) -> RoledIdentifier { - guard let resource = entry.resource else { + private static func entryKey( + in entry: BundleEntry, + index: Int, + document: ValidationDocument + ) throws(ExchangeGraphError) -> RoledIdentifier { + guard entry.resource != nil else { throw .invalidEntries("Bundle entry has no resource") } let entryKeys = entry.extension?.filter { $0.url == Canonicals.entryNodeKey } ?? [] @@ -108,7 +114,7 @@ extension ExchangeGraph { } let typed: [RoledIdentifier] do { - typed = try ExchangeIdentity.typedResourceIdentifiers(in: resource) + typed = try document.typedResourceIdentifiers(at: index) } catch { throw .ruleViolation(.mobileExchangeEntryNodeKey) } @@ -130,15 +136,13 @@ extension ExchangeGraph { private static func validateLiteralReferences( in entries: [BundleEntry], + document: ValidationDocument, resourceTypesByFullURL: [String: String] ) throws(ExchangeGraphError) { - for entry in entries { - guard let resource = entry.resource else { - continue - } - let json: Any + for (index, entry) in entries.enumerated() where entry.resource != nil { + let json: Any? do { - json = try JSONSerialization.jsonObject(with: try JSONEncoder().encode(resource)) + json = try document.resourceObject(at: index) } catch { throw .invalidEntries(String(reflecting: type(of: error))) } @@ -146,9 +150,9 @@ extension ExchangeGraph { throw .ruleViolation(.mobileExchangeContainedResourceProhibited) } var references: [LiteralReference] = [] - ExchangeIdentity.walkJSONObjects(json) { object in - if let reference = object["reference"] as? String, object["identifier"] == nil { - references.append(LiteralReference(value: reference, declaredType: object["type"] as? String)) + ExchangeIdentity.walkJSONObjects(object) { node in + if let reference = node["reference"] as? String, node["identifier"] == nil { + references.append(LiteralReference(value: reference, declaredType: node["type"] as? String)) } } for reference in references { diff --git a/Sources/GroveFHIRContract/ExchangeGraph+EventPolicy.swift b/Sources/GroveFHIRContract/ExchangeGraph+EventPolicy.swift index cd4d8117d..37fb4104f 100644 --- a/Sources/GroveFHIRContract/ExchangeGraph+EventPolicy.swift +++ b/Sources/GroveFHIRContract/ExchangeGraph+EventPolicy.swift @@ -42,12 +42,13 @@ extension ExchangeGraph { static func validateEntryResourcePolicy( kind: ExchangeGraphKind, - entries: [BundleEntry] + entries: [BundleEntry], + document: ValidationDocument ) throws(ExchangeGraphError) { let activeTypes = ExchangeContract.activeOutputResourceTypes .union(ExchangeContract.activeSupportingResourceTypes) .union([ExchangeContract.activeLifecycleResourceType]) - for entry in entries { + for (index, entry) in entries.enumerated() { guard let resource = entry.resource else { throw .invalidEntries("Bundle entry has no resource") } @@ -63,8 +64,7 @@ extension ExchangeGraph { } } do { - let data = try JSONEncoder().encode(resource) - guard let object = try JSONSerialization.jsonObject(with: data) as? [String: Any] + guard let object = try document.resourceObject(at: index) as? [String: Any] else { throw ExchangeGraphError.invalidEntries("Bundle entry resource is not an object") } @@ -132,22 +132,22 @@ extension ExchangeGraph { } } - static func validateActive(entries: [BundleEntry]) throws(ExchangeGraphError) { - try validateActiveProfileClaims(entries: entries) + static func validateActive(entries: [BundleEntry], document: ValidationDocument) throws(ExchangeGraphError) { + try validateActiveProfileClaims(entries: entries, document: document) let provenance = try validatedActiveProvenance(entries: entries) guard hasExactLifecycleCoding(provenance, kind: .active) else { throw .ruleViolation(.mobileExchangeLifecycleCoding) } - let outputs = try validateActiveEntries(entries) - try validateRecordingDocuments(entries, sourceDerivedOutputCount: outputs.resourceTypesByURL.count) - try validateSourceMarkers(entries: entries) + let outputs = try validateActiveEntries(entries, document: document) + try validateRecordingDocuments(entries, sourceDerivedOutputCount: outputs.resourceTypesByURL.count, document: document) + try validateSourceMarkers(entries: entries, document: document) try validateActiveTargets(provenance, resourceTypesByURL: outputs.resourceTypesByURL) let sourceEntity = try exactSourceEntity(in: provenance) guard outputs.sourceRecords.contains(sourceEntity) else { throw .ruleViolation(.mobileExchangeTransformProvenance) } - try validateStudyContext(entries: entries) - try validateSupportingConnectivity(entries: entries) + try validateStudyContext(entries: entries, document: document) + try validateSupportingConnectivity(entries: entries, document: document) } private static func validatedActiveProvenance( @@ -170,12 +170,12 @@ extension ExchangeGraph { } private static func validateActiveEntries( - _ entries: [BundleEntry] + _ entries: [BundleEntry], document: ValidationDocument ) throws(ExchangeGraphError) -> ActiveOutputSummary { var summary = ActiveOutputSummary() do { - for entry in entries { - if let output = try validatedActiveOutput(from: entry) { + for (index, entry) in entries.enumerated() { + if let output = try validatedActiveOutput(from: entry, at: index, document: document) { summary.append(output) } } @@ -194,12 +194,12 @@ extension ExchangeGraph { } private static func validatedActiveOutput( - from entry: BundleEntry + from entry: BundleEntry, at index: Int, document: ValidationDocument ) throws -> ActiveOutput? { guard let key = try entryKey(entry) else { throw ExchangeIdentityError.missingIdentifierSystem } - let identifiers = try ExchangeIdentity.typedResourceIdentifiers(in: entry.resource) + let identifiers = try document.typedResourceIdentifiers(at: index) guard Set(identifiers).count == identifiers.count else { throw ExchangeIdentityError.duplicateEntryIdentifier(key.identifier) } @@ -243,16 +243,15 @@ extension ExchangeGraph { } private static func validateRecordingDocuments( - _ entries: [BundleEntry], - sourceDerivedOutputCount: Int + _ entries: [BundleEntry], sourceDerivedOutputCount: Int, document validationDocument: ValidationDocument ) throws(ExchangeGraphError) { - for entry in entries { + for (index, entry) in entries.enumerated() { guard case .documentReference(let document)? = entry.resource else { continue } let typed: [RoledIdentifier] do { - typed = try ExchangeIdentity.typedResourceIdentifiers(in: entry.resource) + typed = try validationDocument.typedResourceIdentifiers(at: index) } catch { throw .ruleViolation(.sensorRecordingDocumentIdentityAndContent) } @@ -282,16 +281,16 @@ extension ExchangeGraph { } /// An adapter's source marker belongs on that adapter's outputs alone, once each. - private static func validateSourceMarkers(entries: [BundleEntry]) throws(ExchangeGraphError) { + private static func validateSourceMarkers(entries: [BundleEntry], document: ValidationDocument) throws(ExchangeGraphError) { let marker = HealthKitContract.sourceTypeExtension.value?.url.absoluteString let adapterRoot = "\(Canonicals.root)/healthkit/" - for entry in entries { + for (index, entry) in entries.enumerated() { guard let resource = entry.resource, isActiveOutput(resource) else { continue } let extensions: [[String: Any]] do { - let object = try JSONSerialization.jsonObject(with: try JSONEncoder().encode(resource)) as? [String: Any] + let object = try document.resourceObject(at: index) as? [String: Any] extensions = object?["extension"] as? [[String: Any]] ?? [] } catch { throw .invalidEntries(String(reflecting: type(of: error))) @@ -373,9 +372,9 @@ extension ExchangeGraph { } } - static func validateRetraction(entries: [BundleEntry]) throws(ExchangeGraphError) { - for entry in entries { - try validateRetractionEntry(entry) + static func validateRetraction(entries: [BundleEntry], document: ValidationDocument) throws(ExchangeGraphError) { + for (index, entry) in entries.enumerated() { + try validateRetractionEntry(entry, at: index, document: document) } let provenance = try validatedRetractionProvenance(entries: entries) guard !isTransformOnlyLifecycle(provenance) else { @@ -392,7 +391,7 @@ extension ExchangeGraph { } private static func validateRetractionEntry( - _ entry: BundleEntry + _ entry: BundleEntry, at index: Int, document: ValidationDocument ) throws(ExchangeGraphError) { guard let resource = entry.resource else { throw .invalidEntries("Bundle entry has no resource") @@ -406,11 +405,11 @@ extension ExchangeGraph { modes: ProfileClaims.deviceProfileModes, rule: .mobileSupportDeviceProfile ) - try validateIdentifierRoles(in: resource, claim: claim, rule: .mobileDeviceRecordingDeviceDualIdentity) + try validateIdentifierRoles(atEntry: index, document: document, claim: claim, rule: .mobileDeviceRecordingDeviceDualIdentity) guard let key = try? entryKey(entry) else { throw .ruleViolation(.mobileDeviceRecordingDeviceDualIdentity) } - let identifiers = (try? ExchangeIdentity.typedResourceIdentifiers(in: resource)) ?? [] + let identifiers = (try? document.typedResourceIdentifiers(at: index)) ?? [] try validateDeviceIdentity(device, entryKey: key, identifiers: identifiers) default: throw .ruleViolation(.mobileRetractionNoClinicalCopy) diff --git a/Sources/GroveFHIRContract/ExchangeGraph+Profiles.swift b/Sources/GroveFHIRContract/ExchangeGraph+Profiles.swift index cc60e393d..2e47b62fa 100644 --- a/Sources/GroveFHIRContract/ExchangeGraph+Profiles.swift +++ b/Sources/GroveFHIRContract/ExchangeGraph+Profiles.swift @@ -17,14 +17,15 @@ import ModelsR4 extension ExchangeGraph { static func validateActiveProfileClaims( - entries: [BundleEntry] + entries: [BundleEntry], + document: ValidationDocument ) throws(ExchangeGraphError) { var activeProvenance: Provenance? for (index, entry) in entries.enumerated() { guard let resource = entry.resource else { throw .invalidEntries("Bundle entry has no resource") } - if let provenance = try validateActiveProfileClaim(resource, entryIndex: index) { + if let provenance = try validateActiveProfileClaim(resource, entryIndex: index, document: document) { activeProvenance = provenance } } @@ -36,7 +37,8 @@ extension ExchangeGraph { private static func validateActiveProfileClaim( _ resource: ResourceProxy, - entryIndex: Int + entryIndex: Int, + document validationDocument: ValidationDocument ) throws(ExchangeGraphError) -> Provenance? { switch resource { case .observation(let observation): @@ -49,7 +51,8 @@ extension ExchangeGraph { rule: .mobileOutputDocumentProfile ) try validateIdentifierRoles( - in: resource, + atEntry: entryIndex, + document: validationDocument, claim: claim, additionallyAllowed: [.writerRecord], rule: .sensorRecordingDocumentIdentityAndContent @@ -66,7 +69,12 @@ extension ExchangeGraph { modes: ProfileClaims.deviceProfileModes, rule: .mobileSupportDeviceProfile ) - try validateIdentifierRoles(in: resource, claim: claim, rule: .mobileDeviceRecordingDeviceDualIdentity) + try validateIdentifierRoles( + atEntry: entryIndex, + document: validationDocument, + claim: claim, + rule: .mobileDeviceRecordingDeviceDualIdentity + ) case .questionnaireResponse(let response): _ = try validateDirectProfileClaim( profiles: response.meta?.profile ?? [], @@ -77,7 +85,7 @@ extension ExchangeGraph { try validateActiveProvenanceProfile(provenance) return provenance default: - try validateAdapterOnlyOutputProfile(resource) + try validateAdapterOnlyOutputProfile(resource, entryIndex: entryIndex, document: validationDocument) } return nil } @@ -141,13 +149,14 @@ extension ExchangeGraph { } static func validateIdentifierRoles( - in resource: ResourceProxy, + atEntry index: Int, + document: ValidationDocument, claim: DirectProfileClaim, additionallyAllowed: Set = [], rule: ExchangeGraphRule ) throws(ExchangeGraphError) { do { - let identifiers = try ExchangeIdentity.typedResourceIdentifiers(in: resource) + let identifiers = try document.typedResourceIdentifiers(at: index) let roles = identifiers.map(\.role) guard Set(identifiers).count == identifiers.count else { throw ExchangeGraphError.ruleViolation(rule) diff --git a/Sources/GroveFHIRContract/ExchangeGraph+References.swift b/Sources/GroveFHIRContract/ExchangeGraph+References.swift index 8701961ed..c7f3362f8 100644 --- a/Sources/GroveFHIRContract/ExchangeGraph+References.swift +++ b/Sources/GroveFHIRContract/ExchangeGraph+References.swift @@ -39,7 +39,8 @@ extension ExchangeGraph { private static let roleSystem = Canonicals.identifierRoleCodeSystemValue static func validateGovernedReferenceTargets( - entries: [BundleEntry] + entries: [BundleEntry], + document: ValidationDocument ) throws(ExchangeGraphError) { var resourceTypesByFullURL: [String: String] = [:] for entry in entries { @@ -49,9 +50,9 @@ extension ExchangeGraph { } } let context = ReferenceResolutionContext(bundleResourceTypes: resourceTypesByFullURL) - for entry in entries { + for (index, entry) in entries.enumerated() { try validateGovernedReferences(in: entry.resource, context: context) - try validateGovernedExtensions(in: entry.resource, context: context) + try validateGovernedExtensions(in: entry.resource, entryIndex: index, document: document, context: context) } } @@ -257,14 +258,17 @@ extension ExchangeGraph { static func validateGovernedExtensions( in resource: ResourceProxy?, + entryIndex: Int, + document: ValidationDocument, context: ReferenceResolutionContext ) throws(ExchangeGraphError) { - guard let resource else { + guard resource != nil else { return } do { - let data = try JSONEncoder().encode(resource) - let object = try JSONSerialization.jsonObject(with: data) + guard let object = try document.resourceObject(at: entryIndex) else { + return + } try validateGovernedExtensions(in: object, context: context) } catch let error as ExchangeGraphError { throw error diff --git a/Sources/GroveFHIRContract/ExchangeGraph+SerializedPolicy.swift b/Sources/GroveFHIRContract/ExchangeGraph+SerializedPolicy.swift index 4b851cd5e..f9b936ed3 100644 --- a/Sources/GroveFHIRContract/ExchangeGraph+SerializedPolicy.swift +++ b/Sources/GroveFHIRContract/ExchangeGraph+SerializedPolicy.swift @@ -13,9 +13,9 @@ import ModelsR4 extension ExchangeGraph { static func validateSerializedEntryPolicy( kind: ExchangeGraphKind, - data: Data + json: Result ) throws(ExchangeGraphError) { - let root = try serializedBundleObject(data) + let root = try serializedBundleObject(json) let activeTypes = ExchangeContract.activeOutputResourceTypes .union(ExchangeContract.activeSupportingResourceTypes) .union([ExchangeContract.activeLifecycleResourceType]) @@ -32,10 +32,10 @@ extension ExchangeGraph { } } - private static func serializedBundleObject(_ data: Data) throws(ExchangeGraphError) -> [String: Any] { + private static func serializedBundleObject(_ json: Result) throws(ExchangeGraphError) -> [String: Any] { let root: [String: Any] do { - guard let object = try JSONSerialization.jsonObject(with: data) as? [String: Any] else { + guard let object = try json.get() as? [String: Any] else { throw ExchangeGraphError.invalidEntries("Bundle is not a JSON object") } root = object diff --git a/Sources/GroveFHIRContract/ExchangeGraph+StudyContext.swift b/Sources/GroveFHIRContract/ExchangeGraph+StudyContext.swift index 87ad48883..f900ce28a 100644 --- a/Sources/GroveFHIRContract/ExchangeGraph+StudyContext.swift +++ b/Sources/GroveFHIRContract/ExchangeGraph+StudyContext.swift @@ -30,9 +30,9 @@ extension ExchangeGraph { /// A bundled study context is complete: every ResearchStudy names its exact-revision PlanDefinition, /// exactly one ResearchSubject links the graph's subject to it, and each entry sits under its own role. - static func validateStudyContext(entries: [BundleEntry]) throws(ExchangeGraphError) { + static func validateStudyContext(entries: [BundleEntry], document: ValidationDocument) throws(ExchangeGraphError) { var nodes: [String: StudyNode] = [:] - for entry in entries { + for (index, entry) in entries.enumerated() { guard let role = studyContextRole(of: entry) else { continue } @@ -41,7 +41,7 @@ extension ExchangeGraph { resource.resourceType == role.resourceType else { throw .ruleViolation(.mobileSupportStudyContext) } - nodes[fullURL] = StudyNode(role: role, object: try jsonObject(of: resource)) + nodes[fullURL] = StudyNode(role: role, object: try jsonObject(at: index, document: document)) } let studies = nodes.filter { $0.value.role == .researchStudy } let plans = nodes.filter { $0.value.role == .planDefinition } @@ -56,7 +56,7 @@ extension ExchangeGraph { throw .ruleViolation(.mobileSupportStudyContext) } } - let subject = try outputSubject(in: entries) + let subject = try outputSubject(in: entries, document: document) var enrolled: Set = [] for researchSubject in nodes.values where researchSubject.role == .researchSubject { guard let studyURL = (researchSubject.object["study"] as? [String: Any])?["reference"] as? String, @@ -86,13 +86,16 @@ extension ExchangeGraph { } /// What the first output states as its subject, the reference every ResearchSubject must repeat. - private static func outputSubject(in entries: [BundleEntry]) throws(ExchangeGraphError) -> Data? { - for entry in entries { + private static func outputSubject( + in entries: [BundleEntry], + document: ValidationDocument + ) throws(ExchangeGraphError) -> Data? { + for (index, entry) in entries.enumerated() { guard let resource = entry.resource, ExchangeContract.activeOutputResourceTypes.contains(resource.resourceType) else { continue } - guard let subject = try jsonObject(of: resource)["subject"] as? [String: Any] else { + guard let subject = try jsonObject(at: index, document: document)["subject"] as? [String: Any] else { return nil } return try canonicalJSON(subject) @@ -100,9 +103,9 @@ extension ExchangeGraph { return nil } - private static func jsonObject(of resource: ResourceProxy) throws(ExchangeGraphError) -> [String: Any] { + private static func jsonObject(at index: Int, document: ValidationDocument) throws(ExchangeGraphError) -> [String: Any] { do { - return try JSONSerialization.jsonObject(with: try JSONEncoder().encode(resource)) as? [String: Any] ?? [:] + return try document.resourceObject(at: index) as? [String: Any] ?? [:] } catch { throw .invalidEntries(String(reflecting: type(of: error))) } diff --git a/Sources/GroveFHIRContract/ExchangeGraph+SupportIdentity.swift b/Sources/GroveFHIRContract/ExchangeGraph+SupportIdentity.swift index ae51c52ca..72bbda76b 100644 --- a/Sources/GroveFHIRContract/ExchangeGraph+SupportIdentity.swift +++ b/Sources/GroveFHIRContract/ExchangeGraph+SupportIdentity.swift @@ -12,25 +12,28 @@ import ModelsR4 extension ExchangeGraph { static func validateSupportingConnectivity( - entries: [BundleEntry] + entries: [BundleEntry], + document: ValidationDocument ) throws(ExchangeGraphError) { - let resourcePairs: [(String, ResourceProxy)] = entries.compactMap { entry in + let resourcePairs: [(String, (resource: ResourceProxy, index: Int))] = entries.enumerated().compactMap { index, entry in guard let fullURL = entry.fullUrl?.value?.url.absoluteString, let resource = entry.resource else { return nil } - return (fullURL, resource) + return (fullURL, (resource, index)) } - let resourcesByFullURL = [String: ResourceProxy]( + let entriesByFullURL = [String: (resource: ResourceProxy, index: Int)]( uniqueKeysWithValues: resourcePairs ) + let resourcesByFullURL = entriesByFullURL.mapValues(\.resource) var adjacency = [String: Set]( uniqueKeysWithValues: resourcesByFullURL.keys.map { ($0, Set()) } ) do { - for (fullURL, resource) in resourcesByFullURL { - let data = try JSONEncoder().encode(resource) - let object = try JSONSerialization.jsonObject(with: data) + for (fullURL, entry) in entriesByFullURL { + guard let object = try document.resourceObject(at: entry.index) else { + continue + } var references: Set = [] collectLiteralReferences(in: object, into: &references) for reference in references where resourcesByFullURL[reference] != nil { @@ -75,15 +78,16 @@ extension ExchangeGraph { } static func validateAdapterOnlyOutputProfile( - _ resource: ResourceProxy + _ resource: ResourceProxy, + entryIndex: Int, + document: ValidationDocument ) throws(ExchangeGraphError) { guard let expected = ProfileClaims.adapterOnlyOutputProfiles[resource.resourceType], let expectedProfile = expected.value?.url.absoluteString else { return } do { - let data = try JSONEncoder().encode(resource) - let object = try JSONSerialization.jsonObject(with: data) as? [String: Any] + let object = try document.resourceObject(at: entryIndex) as? [String: Any] let meta = object?["meta"] as? [String: Any] let profiles = meta?["profile"] as? [String] guard profiles == [expectedProfile] else { diff --git a/Sources/GroveFHIRContract/ExchangeGraph+ValidationDocument.swift b/Sources/GroveFHIRContract/ExchangeGraph+ValidationDocument.swift new file mode 100644 index 000000000..cf0cd277d --- /dev/null +++ b/Sources/GroveFHIRContract/ExchangeGraph+ValidationDocument.swift @@ -0,0 +1,118 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +import Foundation +import ModelsR4 + + +extension ExchangeGraph { + /// The JSON view of one graph, parsed once and shared by every validation pass. + /// + /// The JSON checks were written against standalone encodes of each entry's resource. An entry's + /// `resource` member of the encoded Bundle is that same encode, so the passes read it from here + /// instead of each re-encoding and re-parsing every resource. An entry the parsed Bundle does not + /// line up with falls back to the standalone encode, which is what every pass did before. + final class ValidationDocument { + private enum ResourceSource { + case absent + case parsed(Any) + case standalone(ResourceProxy) + } + + private let bundleJSON: Result + private let resources: [ResourceSource] + private var identifierCache: [Int: [Result]] = [:] + private var typedIdentifierCache: [Int: Result<[RoledIdentifier], any Error>] = [:] + + /// - Parameters: + /// - bundle: The Bundle the passes validate. + /// - jsonData: The encoding of exactly `bundle`, when the caller already has it; `nil` encodes it here. + init(bundle: ModelsR4.Bundle, jsonData: Data?) { + let bundleJSON = Result { + try JSONSerialization.jsonObject(with: jsonData ?? JSONEncoder().encode(bundle)) + } + let rawEntries = ((try? bundleJSON.get()) as? [String: Any])?["entry"] as? [Any] + self.bundleJSON = bundleJSON + self.resources = (bundle.entry ?? []).enumerated().map { index, entry in + guard let resource = entry.resource else { + return .absent + } + guard let rawEntries, rawEntries.indices.contains(index), + let object = (rawEntries[index] as? [String: Any])?["resource"] else { + return .standalone(resource) + } + return .parsed(object) + } + } + + /// The parsed JSON of the whole Bundle. + func bundleObject() throws -> Any { + try bundleJSON.get() + } + + /// The parsed JSON of the resource of the entry at `index` of `Bundle.entry`, or `nil` if it has none. + func resourceObject(at index: Int) throws -> Any? { + guard resources.indices.contains(index) else { + return nil + } + switch resources[index] { + case .absent: + return nil + case .parsed(let object): + return object + case .standalone(let resource): + return try JSONSerialization.jsonObject(with: JSONEncoder().encode(resource)) + } + } + + /// Each element of the resource's `identifier` array, decoded as an Identifier, in order. + /// + /// A member that fails to decode keeps its error in place, so a pass that stops at an earlier + /// member still reports what it reported before. + func resourceIdentifiers(at index: Int) throws -> [Result] { + if let cached = identifierCache[index] { + return cached + } + let object = try resourceObject(at: index) as? [String: Any] + let rawIdentifiers = object?["identifier"] as? [[String: Any]] ?? [] + let identifiers = rawIdentifiers.map { rawIdentifier in + Result { + try JSONDecoder().decode(Identifier.self, from: JSONSerialization.data(withJSONObject: rawIdentifier)) + } + } + identifierCache[index] = identifiers + return identifiers + } + + /// The identifiers of the entry's resource whose `Identifier.type` carries a Grove identifier role. + /// + /// A malformed Grove-typed identifier fails closed. Untyped business identifiers are not part + /// of the exchange identity graph and are intentionally omitted. + func typedResourceIdentifiers(at index: Int) throws -> [RoledIdentifier] { + if let cached = typedIdentifierCache[index] { + return try cached.get() + } + let result = Result<[RoledIdentifier], any Error> { + var identifiers: [RoledIdentifier] = [] + for decoded in try resourceIdentifiers(at: index) { + let identifier = try decoded.get() + let carriesGroveRole = identifier.type?.coding?.contains { + $0.system?.value?.url.absoluteString == Canonicals.identifierRoleCodeSystemValue + } == true + guard carriesGroveRole else { + continue + } + identifiers.append(try RoledIdentifier(identifier)) + } + return identifiers + } + typedIdentifierCache[index] = result + return try result.get() + } + } +} diff --git a/Sources/GroveFHIRContract/ExchangeGraph.swift b/Sources/GroveFHIRContract/ExchangeGraph.swift index 615e52ea1..407cea94f 100644 --- a/Sources/GroveFHIRContract/ExchangeGraph.swift +++ b/Sources/GroveFHIRContract/ExchangeGraph.swift @@ -43,17 +43,24 @@ public struct ExchangeGraph: Sendable { eventIdentifier: ExchangeEventIdentifier, bundle: ModelsR4.Bundle ) throws(ExchangeGraphError) { - let jsonData: Data - do { - jsonData = try JSONEncoder().encode(bundle) - } catch { - throw .invalidEntries(String(reflecting: type(of: error))) + self.jsonData = try Self.drainingTemporaries { () throws(ExchangeGraphError) in + let jsonData: Data + do { + jsonData = try JSONEncoder().encode(bundle) + } catch { + throw .invalidEntries(String(reflecting: type(of: error))) + } + try Self.validate( + kind: kind, + eventIdentifier: eventIdentifier, + bundle: bundle, + document: ValidationDocument(bundle: bundle, jsonData: jsonData) + ) + return jsonData } - try Self.validate(kind: kind, eventIdentifier: eventIdentifier, bundle: bundle) self.kind = kind self.eventIdentifier = eventIdentifier self.bundle = bundle - self.jsonData = jsonData } /// Re-validates stored or received JSON before it is trusted again. @@ -65,15 +72,27 @@ public struct ExchangeGraph: Sendable { kind: ExchangeGraphKind, jsonData: Data ) throws(ExchangeGraphError) { + (self.eventIdentifier, self.bundle) = try Self.drainingTemporaries { () throws(ExchangeGraphError) in + try Self.decodeValidated(kind: kind, jsonData: jsonData) + } + self.kind = kind + self.jsonData = jsonData + } + + private static func decodeValidated( + kind: ExchangeGraphKind, + jsonData: Data + ) throws(ExchangeGraphError) -> (ExchangeEventIdentifier, ModelsR4.Bundle) { do { var scanner = StrictJSONScanner(jsonData) try scanner.validate() } catch { throw .invalidEntries("Serialized event is not strict JSON") } - try Self.validateSerializedEntryPolicy(kind: kind, data: jsonData) + let serialized = Result { try JSONSerialization.jsonObject(with: jsonData) } + try Self.validateSerializedEntryPolicy(kind: kind, json: serialized) do { - try ExchangeIdentity.validateSerializedIdentifierSystems(in: jsonData) + try ExchangeIdentity.validateSerializedIdentifierSystems(inJSON: serialized.get()) } catch { throw .ruleViolation(.mobileExchangeOpaqueResourceIdentity) } @@ -92,25 +111,47 @@ public struct ExchangeGraph: Sendable { } catch { throw .ruleViolation(.mobileExchangeEventIdentity) } - try Self.validate(kind: kind, eventIdentifier: eventIdentifier, bundle: decodedBundle) - self.kind = kind - self.eventIdentifier = eventIdentifier - self.bundle = decodedBundle - self.jsonData = jsonData + // The model checks read the decoded model's own encoding, not the stored bytes: those may still + // carry members the model does not keep, and the checks decide over what the graph will hold. + try Self.validate( + kind: kind, + eventIdentifier: eventIdentifier, + bundle: decodedBundle, + document: ValidationDocument(bundle: decodedBundle, jsonData: nil) + ) + return (eventIdentifier, decodedBundle) + } + + /// Runs `body` in its own autorelease pool where there is one, so the Foundation temporaries of + /// encoding, parsing and validating one graph are released with that graph rather than with the + /// caller's pool, which a batch conversion may not drain until thousands of graphs later. + private static func drainingTemporaries( + _ body: () throws(ExchangeGraphError) -> T + ) throws(ExchangeGraphError) -> T { + #if canImport(ObjectiveC) + // `autoreleasepool` rethrows untyped errors, so the typed error crosses it inside a Result. + let result = autoreleasepool { + Result { () throws(ExchangeGraphError) in try body() } + } + return try result.get() + #else + return try body() + #endif } private static func validate( kind: ExchangeGraphKind, eventIdentifier: ExchangeEventIdentifier, - bundle: ModelsR4.Bundle + bundle: ModelsR4.Bundle, + document: ValidationDocument ) throws(ExchangeGraphError) { try validateHeader(bundle, eventIdentifier: eventIdentifier) let entries = try validatedEntries(bundle, kind: kind) - try validateEntryResourcePolicy(kind: kind, entries: entries) + try validateEntryResourcePolicy(kind: kind, entries: entries, document: document) try validateEntryNodeDigests(entries: entries, eventIdentifier: eventIdentifier) - try validateEntryIdentities(in: bundle, entries: entries) - try validateGovernedReferenceTargets(entries: entries) - try validateLifecycle(kind: kind, entries: entries) + try validateEntryIdentities(entries: entries, document: document) + try validateGovernedReferenceTargets(entries: entries, document: document) + try validateLifecycle(kind: kind, entries: entries, document: document) } private static func validateHeader( @@ -165,29 +206,30 @@ public struct ExchangeGraph: Sendable { } private static func validateEntryIdentities( - in bundle: ModelsR4.Bundle, - entries: [BundleEntry] + entries: [BundleEntry], + document: ValidationDocument ) throws(ExchangeGraphError) { - try validateResourceIdentifiers(entries: entries) + try validateResourceIdentifiers(entries: entries, document: document) do { - try ExchangeIdentity.validateIdentifierSystemRoles(in: bundle) + try ExchangeIdentity.validateIdentifierSystemRoles(inBundleJSON: document.bundleObject()) } catch let error as ExchangeIdentityError { throw .ruleViolation(Self.rule(for: error)) } catch { throw .invalidEntries(String(reflecting: type(of: error))) } - try validateEntryKeys(entries: entries) + try validateEntryKeys(entries: entries, document: document) } private static func validateLifecycle( kind: ExchangeGraphKind, - entries: [BundleEntry] + entries: [BundleEntry], + document: ValidationDocument ) throws(ExchangeGraphError) { switch kind { case .active: - try Self.validateActive(entries: entries) + try Self.validateActive(entries: entries, document: document) case .retraction: - try Self.validateRetraction(entries: entries) + try Self.validateRetraction(entries: entries, document: document) } } diff --git a/Sources/GroveFHIRContract/ExchangeIdentity.swift b/Sources/GroveFHIRContract/ExchangeIdentity.swift index 500b983f8..55d709d28 100644 --- a/Sources/GroveFHIRContract/ExchangeIdentity.swift +++ b/Sources/GroveFHIRContract/ExchangeIdentity.swift @@ -94,9 +94,9 @@ package enum ExchangeIdentity { /// /// The check walks nested identifier-only References and Provenance entities as well as /// top-level resource and entry identifiers. Untyped and non-Grove identifiers remain open. - static func validateIdentifierSystemRoles(in bundle: ModelsR4.Bundle) throws { - let data = try JSONEncoder().encode(bundle) - let json = try JSONSerialization.jsonObject(with: data) + /// + /// - Parameter json: The parsed JSON of the whole Bundle. + static func validateIdentifierSystemRoles(inBundleJSON json: Any) throws { var roleBySystem: [String: GroveIdentifierRole] = [:] try walkJSONObjects(json) { object in guard let type = object["type"] as? [String: Any], @@ -150,7 +150,11 @@ package enum ExchangeIdentity { /// stored bytes are checked before model decoding can accept a noncanonical identity in /// normalized form. package static func validateSerializedIdentifierSystems(in data: Data) throws { - let json = try JSONSerialization.jsonObject(with: data) + try validateSerializedIdentifierSystems(inJSON: JSONSerialization.jsonObject(with: data)) + } + + /// ``validateSerializedIdentifierSystems(in:)`` over JSON already parsed from the stored bytes. + static func validateSerializedIdentifierSystems(inJSON json: Any) throws { try walkJSONObjects(json) { object in guard let type = object["type"] as? [String: Any], let codings = type["coding"] as? [[String: Any]], @@ -180,36 +184,3 @@ package enum ExchangeIdentity { return true } } - - -extension ExchangeIdentity { - /// Returns the identifiers whose `Identifier.type` carries a Grove identifier role. - /// - /// A malformed Grove-typed identifier fails closed. Untyped business identifiers are not part - /// of the exchange identity graph and are intentionally omitted. - static func typedResourceIdentifiers( - in resource: ResourceProxy? - ) throws -> [RoledIdentifier] { - guard let resource else { - return [] - } - let data = try JSONEncoder().encode(resource) - guard let object = try JSONSerialization.jsonObject(with: data) as? [String: Any], - let rawIdentifiers = object["identifier"] as? [[String: Any]] else { - return [] - } - var identifiers: [RoledIdentifier] = [] - for rawIdentifier in rawIdentifiers { - let data = try JSONSerialization.data(withJSONObject: rawIdentifier) - let identifier = try JSONDecoder().decode(Identifier.self, from: data) - let carriesGroveRole = identifier.type?.coding?.contains { - $0.system?.value?.url.absoluteString == Canonicals.identifierRoleCodeSystemValue - } == true - guard carriesGroveRole else { - continue - } - identifiers.append(try RoledIdentifier(identifier)) - } - return identifiers - } -} diff --git a/Sources/GroveFHIRContract/String+PlainDecimal.swift b/Sources/GroveFHIRContract/String+Utils.swift similarity index 80% rename from Sources/GroveFHIRContract/String+PlainDecimal.swift rename to Sources/GroveFHIRContract/String+Utils.swift index 87bf83837..f9adad161 100644 --- a/Sources/GroveFHIRContract/String+PlainDecimal.swift +++ b/Sources/GroveFHIRContract/String+Utils.swift @@ -57,3 +57,24 @@ extension String { self = isNegative ? "-" + magnitude : magnitude } } + + +extension StringProtocol { + /// Same result as `trimmingCharacters(in: .whitespacesAndNewlines).isEmpty`. + /// Uses the same set as `CharacterSet.whitespacesAndNewlines` (Unicode White_Space + U+200B). + var isBlank: Bool { + @specialized(where Self == String) + @specialized(where Self == Substring) + get { + unicodeScalars.allSatisfy { + switch $0.value { + case 0x09...0x0D, 0x20, 0x85, 0xA0, 0x1680, 0x2000...0x200B, + 0x2028, 0x2029, 0x202F, 0x205F, 0x3000: + true + default: + false + } + } + } + } +} diff --git a/Tests/GroveHealthKitFHIRTests/ExchangeGraphValidationDocumentTests.swift b/Tests/GroveHealthKitFHIRTests/ExchangeGraphValidationDocumentTests.swift new file mode 100644 index 000000000..309a939a4 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ExchangeGraphValidationDocumentTests.swift @@ -0,0 +1,171 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) && !os(watchOS) + +import Darwin +import Foundation +@testable import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit +import ModelsR4 +import Testing + + +/// Pins what the shared validation JSON may stand in for, and that a graph releases its own temporaries. +@Suite +struct ExchangeGraphValidationDocumentTests { + enum Scenario: String, CaseIterable, CustomTestStringConvertible { + case heartRate + case heartRateWithStudies + case gatewayHeartRateWithDevice + case bloodPressure + + var testDescription: String { rawValue } + } + + private static let timestamp = Date(timeIntervalSince1970: 1_787_148_600) + private static let beatsPerMinute = HKUnit.count().unitDivided(by: .minute()) + + private static func conversions(_ scenario: Scenario) throws -> HealthKitConversionSet { + let converter = HealthKitConverter() + switch scenario { + case .heartRate: + return try converter.convert(heartRateSample(), context: context()) + case .heartRateWithStudies: + return try converter.convert(heartRateSample(), context: context(studies: [.test("a"), .test("b")])) + case .gatewayHeartRateWithDevice: + return try converter.convert( + heartRateSample(device: HKDevice( + name: "Band", + manufacturer: "Example Device Company", + model: "Band One", + hardwareVersion: nil, + firmwareVersion: nil, + softwareVersion: nil, + localIdentifier: "band-1", + udiDeviceIdentifier: nil + )), + context: context(converterWasGateway: true) + ) + case .bloodPressure: + let dates = (start: timestamp, end: timestamp.addingTimeInterval(60)) + func pressure(_ type: HKQuantityTypeIdentifier, _ value: Double) -> HKQuantitySample { + HKQuantitySample( + type: HKQuantityType(type), + quantity: HKQuantity(unit: .millimeterOfMercury(), doubleValue: value), + start: dates.start, + end: dates.end + ) + } + return try converter.convert( + HKCorrelation( + type: HKCorrelationType(.bloodPressure), + start: dates.start, + end: dates.end, + objects: [pressure(.bloodPressureSystolic, 118), pressure(.bloodPressureDiastolic, 76)] + ), + context: context() + ) + } + } + + private static func context( + studies: [StudyEnrollment] = [], + converterWasGateway: Bool = false + ) -> HealthKitConversionContext { + HealthKitConversionContext( + subject: .testPatient, + graphIdentifierSystem: "https://study.example.org/fhir/identifiers/mobile-graph", + converterWasGateway: converterWasGateway, + conversionInstant: timestamp, + recordingDeviceStableUnitToken: "band", + studies: studies + ) + } + + private static func heartRateSample(device: HKDevice? = nil) -> HKQuantitySample { + HKQuantitySample( + type: HKQuantityType(.heartRate), + quantity: HKQuantity(unit: beatsPerMinute, doubleValue: 72), + start: timestamp, + end: timestamp.addingTimeInterval(60), + device: device, + metadata: nil + ) + } + + private static func expectSharedJSONMatchesStandaloneEncodes(_ graph: ExchangeGraph) throws { + let entries = try #require(graph.bundle.entry) + #expect(entries.count > 1) + let documents = [ + ExchangeGraph.ValidationDocument(bundle: graph.bundle, jsonData: graph.jsonData), + ExchangeGraph.ValidationDocument(bundle: graph.bundle, jsonData: nil) + ] + for document in documents { + for (index, entry) in entries.enumerated() { + let resource = try #require(entry.resource) + let standalone = try JSONSerialization.jsonObject(with: JSONEncoder().encode(resource)) + let shared = try #require(try document.resourceObject(at: index)) + #expect(try canonical(shared) == canonical(standalone), "Bundle.entry[\(index)]") + #expect((shared as? NSDictionary) == (standalone as? NSDictionary), "Bundle.entry[\(index)]") + } + let bundle = try JSONSerialization.jsonObject(with: JSONEncoder().encode(graph.bundle)) + #expect(try canonical(document.bundleObject()) == canonical(bundle)) + #expect(try document.resourceObject(at: entries.count) == nil) + } + } + + private static func canonical(_ object: Any) throws -> Data { + try JSONSerialization.data(withJSONObject: object, options: [.sortedKeys]) + } + + private static func liveHeapBytes() -> Int { + var statistics = malloc_statistics_t() + malloc_zone_statistics(nil, &statistics) + return Int(statistics.size_in_use) + } + + @Test("An entry's resource in the parsed Bundle is the standalone encode of that resource", arguments: Scenario.allCases) + func parsedEntryResourceIsTheStandaloneEncode(scenario: Scenario) throws { + for graph in try Self.conversions(scenario).all.map(\.graph) { + try Self.expectSharedJSONMatchesStandaloneEncodes(graph) + } + } + + /// A graph's Foundation temporaries (its parsed JSON trees) would otherwise stay in the caller's pool until a + /// whole batch finishes: ~44 KB per graph here without the graph's own pool, ~2 KB with it. Live heap bytes are + /// process-wide and other suites run concurrently, so the smallest growth over two rounds is held to a bound + /// well between the two. + @Test( + "Building a graph leaves no Foundation temporaries in the caller's autorelease pool", + .disabled(if: ProcessInfo.processInfo.environment["CI"] != nil, "Process-wide heap measurement is too noisy on shared CI runners") + ) + func graphValidationDrainsItsOwnTemporaries() throws { + let converter = HealthKitConverter() + let context = Self.context() + let sample = Self.heartRateSample() + let stored = try converter.convert(sample, context: context).primary.graph.jsonData + let iterations = 500 + let round = { () throws -> Int in + try autoreleasepool { + let before = Self.liveHeapBytes() + for _ in 0.. Date: Sat, 3 Oct 2026 11:45:06 +0200 Subject: [PATCH 002/220] Pin the HealthKit Exchange Graphs as Golden Fixtures Add a test-only factory for stored HealthKit samples with chosen UUIDs, source revisions and devices, and pin the converter's output for 40 shapes (observations, writers, disclosures, documents, retractions) as checked-in goldens compared with lossless-token equality. Check in the conversion throughput benchmark, gated behind GROVE_FHIR_BENCH_RUN. Co-Authored-By: Claude Fable 5.1 --- Package.swift | 3 + REUSE.toml | 1 + ...onversionThroughputBenchmark+Support.swift | 327 ++ .../ConversionThroughputBenchmark.swift | 508 ++++ .../GoldenGraphCases+Documents.swift | 247 ++ .../GoldenGraphCases.swift | 248 ++ .../GoldenGraphFixtures.swift | 237 ++ .../GoldenGraphTests.swift | 318 ++ .../Goldens/blood-pressure-correlation.json | 482 +++ .../Goldens/body-mass-user-entered.json | 358 +++ .../Goldens/bundled-patient-subject.json | 632 ++++ .../Resources/Goldens/clinical-document.json | 356 +++ .../electrocardiogram-symptom-companion.json | 613 ++++ .../electrocardiogram-with-symptom.json | 764 +++++ .../Resources/Goldens/electrocardiogram.json | 747 +++++ .../Goldens/gateway-application-role.json | 687 +++++ .../Resources/Goldens/gateway-role.json | 612 ++++ .../heart-rate-device-without-unit-token.json | 350 +++ .../Goldens/heart-rate-interval.json | 350 +++ .../Resources/Goldens/heart-rate-minimal.json | 342 +++ .../Goldens/heart-rate-motion-context.json | 476 +++ .../Goldens/heart-rate-no-time-zone.json | 446 +++ .../Goldens/heart-rate-recording-device.json | 454 +++ .../Resources/Goldens/heart-rate-study.json | 458 +++ .../Resources/Goldens/heartbeat-series.json | 612 ++++ .../Goldens/insulin-delivery-bolus.json | 371 +++ .../Goldens/native-identifier-disclosure.json | 610 ++++ .../Resources/Goldens/outlines.json | 2650 +++++++++++++++++ .../Goldens/repository-ids-on-every-node.json | 614 ++++ .../Goldens/retraction-blood-pressure.json | 135 + .../Goldens/retraction-electrocardiogram.json | 154 + ...traction-heart-rate-native-identifier.json | 143 + .../Goldens/retraction-heart-rate.json | 133 + .../Resources/Goldens/sleep-analysis.json | 473 +++ .../Resources/Goldens/state-of-mind.json | 423 +++ .../Resources/Goldens/step-count-period.json | 465 +++ .../Resources/Goldens/sync-identity.json | 622 ++++ .../Goldens/two-study-enrollments.json | 822 +++++ .../Resources/Goldens/udi-disclosure.json | 611 ++++ .../Resources/Goldens/workout-route.json | 612 ++++ .../writer-blank-name-with-sync-identity.json | 470 +++ ...assification-without-recording-device.json | 350 +++ .../Goldens/writer-device-classification.json | 470 +++ .../Goldens/writer-foreign-application.json | 606 ++++ .../writer-host-equals-converter-host.json | 548 ++++ .../writer-self-build-equals-revision.json | 618 ++++ .../Goldens/writer-self-older-build.json | 618 ++++ .../Goldens/writer-self-token-identical.json | 470 +++ .../Goldens/writer-without-version.json | 592 ++++ .../StoredSampleFixtures.swift | 163 + .../StoredSampleFixturesTests.swift | 124 + 51 files changed, 24495 insertions(+) create mode 100644 Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark+Support.swift create mode 100644 Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark.swift create mode 100644 Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift create mode 100644 Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift create mode 100644 Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift create mode 100644 Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/blood-pressure-correlation.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/body-mass-user-entered.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/bundled-patient-subject.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/clinical-document.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram-symptom-companion.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram-with-symptom.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/gateway-application-role.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/gateway-role.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-device-without-unit-token.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-interval.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-minimal.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-motion-context.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-no-time-zone.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-recording-device.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-study.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/heartbeat-series.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/insulin-delivery-bolus.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/native-identifier-disclosure.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/repository-ids-on-every-node.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/retraction-blood-pressure.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/retraction-electrocardiogram.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/retraction-heart-rate-native-identifier.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/retraction-heart-rate.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/sleep-analysis.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/state-of-mind.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/step-count-period.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/sync-identity.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/two-study-enrollments.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/udi-disclosure.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/workout-route.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-blank-name-with-sync-identity.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-device-classification-without-recording-device.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-device-classification.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-foreign-application.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-host-equals-converter-host.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-self-build-equals-revision.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-self-older-build.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-self-token-identical.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-without-version.json create mode 100644 Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift create mode 100644 Tests/GroveHealthKitFHIRTests/StoredSampleFixturesTests.swift diff --git a/Package.swift b/Package.swift index f25647cf7..50b04f9a9 100644 --- a/Package.swift +++ b/Package.swift @@ -385,6 +385,9 @@ var targets: [Target] = [ .target(name: "GroveHealthKitFHIR") ], exclude: testTargetExcludes("GroveHealthKitFHIRTests", additional: ["UITests"]), + resources: [ + .process("Resources") + ], swiftSettings: defaultSwiftSettings, plugins: [] + defaultPlugins ), diff --git a/REUSE.toml b/REUSE.toml index 7027fa7a8..5a7592882 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -39,6 +39,7 @@ SPDX-License-Identifier = "MIT" path = [ "Sources/GroveSpeechRecognizer/Resources/**", "Tests/GroveChatTests/UITests/TestApp/Resources/**", + "Tests/GroveHealthKitFHIRTests/Resources/**", "Tests/GroveQuestionnaireTests/Resources/**", "Tests/GroveQuestionnaireExtractionTests/Resources/**", "Tests/GroveQuestionnaireTests/UITests/TestApp/Resources/**" diff --git a/Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark+Support.swift b/Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark+Support.swift new file mode 100644 index 000000000..a6cc9de37 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark+Support.swift @@ -0,0 +1,327 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +// The workloads, scopes and instruments of `ConversionThroughputBenchmark`; see that file for how to run it. +// swiftlint:disable force_try + +#if canImport(HealthKit) + +import CryptoKit +@preconcurrency import Darwin +import Foundation +import GroveFHIRContract +import GroveHealthKitFHIR +import HealthKit +import ModelsR4 + + +enum BenchEnvironment { + static let environment = ProcessInfo.processInfo.environment + static let isEnabled = environment["GROVE_FHIR_BENCH_RUN"] == "1" + static let sampleCount = environment["GROVE_FHIR_BENCH_N"].flatMap(Int.init) ?? 5_000 + static let runs = environment["GROVE_FHIR_BENCH_RUNS"].flatMap(Int.init) ?? 3 + static let only = environment["GROVE_FHIR_BENCH_ONLY"] + static let outputPath = environment["GROVE_FHIR_BENCH_OUT"] + static let dumpDirectory = environment["GROVE_FHIR_BENCH_DUMP"] + /// "convert" or "graph-init": loop that phase for `profileSeconds` so an external profiler can attach. + static let profile = environment["GROVE_FHIR_BENCH_PROFILE"] + static let profileSeconds = environment["GROVE_FHIR_BENCH_PROFILE_SECONDS"].flatMap(Double.init) ?? 20 +} + + +/// Collects result lines, prints them and optionally appends them to a file. +final class BenchReport { + private var lines: [String] = [] + + func line(_ text: String) { + lines.append(text) + print("BENCH \(text)") + } + + func flush() { + guard let path = BenchEnvironment.outputPath else { + return + } + let text = lines.joined(separator: "\n") + "\n" + if let handle = FileHandle(forWritingAtPath: path) { + handle.seekToEndOfFile() + handle.write(Data(text.utf8)) + try? handle.close() + } else { + try? Data(text.utf8).write(to: URL(fileURLWithPath: path)) + } + } +} + + +enum Memory { + /// The process's current and lifetime-peak physical footprint, in bytes. + static func footprint() -> (current: UInt64, peak: UInt64) { + var info = task_vm_info_data_t() + var count = mach_msg_type_number_t(MemoryLayout.size / MemoryLayout.size) + let result = withUnsafeMutablePointer(to: &info) { pointer in + pointer.withMemoryRebound(to: integer_t.self, capacity: Int(count)) { + task_info(mach_task_self_, task_flavor_t(TASK_VM_INFO), $0, &count) + } + } + guard result == KERN_SUCCESS else { + return (0, 0) + } + return (info.phys_footprint, UInt64(max(0, info.ledger_phys_footprint_peak))) + } + + static func megabytes(_ bytes: UInt64) -> String { + String(format: "%.1f", Double(bytes) / 1_048_576) + } +} + + +enum Stopwatch { + /// Seconds `body` took on the monotonic clock. + static func seconds(_ body: () throws -> Void) rethrows -> Double { + let start = DispatchTime.now().uptimeNanoseconds + try body() + return Double(DispatchTime.now().uptimeNanoseconds - start) / 1_000_000_000 + } +} + + +/// How one scenario's event contexts are configured. +enum ContextStyle: String { + /// The suite's default fixture: logical subject, no study, every disclosure omitted. + case minimal + /// What MyHeartCounts configures: one study enrollment (three bundled study entries), the native + /// HealthKit UUID disclosed under a deployment system, and a repository id on the Bundle. + case deployment +} + + +struct Scenario { + let name: String + let style: ContextStyle + let samples: [HKSample] +} + + +enum SampleFactory { + static let start = Date(timeIntervalSince1970: 1_786_000_000) + + /// A watch as HealthKit reports it: named, but without a per-unit local identifier. + static let watchWithoutUnitToken = HKDevice( + name: "Apple Watch", + manufacturer: "Apple Inc.", + model: "Watch", + hardwareVersion: "Watch7,5", + firmwareVersion: nil, + softwareVersion: "11.2", + localIdentifier: nil, + udiDeviceIdentifier: nil + ) + + /// A device that names a stable unit, so the graph carries a recording Device entry. + static let deviceWithUnitToken = HKDevice( + name: "Bench Sensor", + manufacturer: "Example Devices", + model: "Sensor One", + hardwareVersion: "1.0", + firmwareVersion: "2.0", + softwareVersion: "3.0", + localIdentifier: "bench-sensor-unit-0001", + udiDeviceIdentifier: nil + ) + + static func heartRate(count: Int, device: HKDevice?, metadata: [String: Any]?) -> [HKSample] { // swiftlint:disable:this discouraged_optional_collection + let unit = HKUnit.count().unitDivided(by: .minute()) + return (0.. [HKSample] { + (0.. [HKSample] { + (0.. HealthKitConversionContext { + let event = try! ExchangeEventIdentifier( + system: systems.event, + producerInstance: Self.producerInstance, + sequence: EventSequence(sequence) + ) + let instant = ExchangeEventContext.testInstant.addingTimeInterval(Double(sequence) / 1_000) + switch style { + case .minimal: + return HealthKitConversionContext( + event: ExchangeEventContext( + subject: subject, + event: event, + identityScope: identityScope, + repositoryScope: repositoryScope, + application: application, + host: host, + conversionInstant: instant + ) + ) + case .deployment: + return HealthKitConversionContext( + event: ExchangeEventContext( + subject: subject, + event: event, + identityScope: identityScope, + repositoryScope: repositoryScope, + application: application, + host: host, + conversionInstant: instant, + studies: studies, + repositoryIDs: [.bundle: try! RepositoryID(sample.uuid.uuidString)] + ), + options: HealthKitConversionOptions( + nativeIdentifierDisclosure: .authorized(system: Self.nativeRecordSystem) + ) + ) + } + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark.swift b/Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark.swift new file mode 100644 index 000000000..4242fa3aa --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark.swift @@ -0,0 +1,508 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +// Baseline-throughput benchmark of the HealthKit -> FHIR converter. It never runs in a normal test run: +// the suite is enabled only when GROVE_FHIR_BENCH_RUN=1 reaches the test process. +// +// Running it in RELEASE mode, which is the only configuration whose numbers mean anything: +// +// (1) Through Xcode on the plain checkout, with the shared build cache (`xcodebuild` forwards only +// TEST_RUNNER_-prefixed variables into the test process; Release needs testability for @testable, and +// matches the macOS destination only without an `arch=` qualifier). Verified on 2026-10-03: +// +// cd && GROVE_LOWERED_DEPLOYMENT_TARGETS=0 GROVE_ENABLE_DEFAULT_PACKAGE_TRAITS=1 \ +// GROVE_EXCLUDE_DOCC_CATALOGS=1 \ +// TEST_RUNNER_GROVE_FHIR_BENCH_RUN=1 TEST_RUNNER_GROVE_FHIR_BENCH_N=5000 TEST_RUNNER_GROVE_FHIR_BENCH_RUNS=3 \ +// TEST_RUNNER_GROVE_FHIR_BENCH_OUT=/tmp/bench-results.txt \ +// xcodebuild test -scheme Grove-Tests -testPlan GroveHealthKitFHIR \ +// -only-testing:GroveHealthKitFHIRTests/ConversionThroughputBenchmark \ +// -configuration Release ENABLE_TESTABILITY=YES ARCHS=arm64 MACOSX_DEPLOYMENT_TARGET=26.0 \ +// -destination 'platform=macOS' -derivedDataPath "$PWD/.derivedData" -packageCachePath "$PWD/.packageCache" \ +// -skipMacroValidation -skipPackagePluginValidation 2>&1 | grep '^BENCH\|error:' +// +// (2) Through SwiftPM in a scratch build directory outside the checkout. `swift test` builds every test +// target of the monorepo, so this route is practical only with a manifest that shrinks the graph to this +// test target's closure. The checked-in manifest has no such switch; the first measurements used a scratch +// copy whose GROVE_FHIR_BENCH=1 block did that. With such a manifest: +// +// cd && GROVE_FHIR_BENCH=1 GROVE_EXCLUDE_DOCC_CATALOGS=1 GROVE_FHIR_BENCH_RUN=1 \ +// xcrun swift test -c release -Xswiftc -enable-testing --scratch-path \ +// --filter ConversionThroughputBenchmark +// +// Use `xcrun swift`, never a bare `swift`: a swiftly-managed toolchain cannot load this manifest against +// the current SDK. A tree that predates ExchangeGraph.ValidationDocument needs `-Xswiftc -DGROVE_BENCH_NO_PASS_TIMING`. +// +// Environment (plain names under SwiftPM, TEST_RUNNER_-prefixed under xcodebuild): +// GROVE_FHIR_BENCH_RUN=1 enable +// GROVE_FHIR_BENCH_N=5000 samples per quantity scenario (workouts use N/10, at least 100) +// GROVE_FHIR_BENCH_RUNS=3 timed repetitions of the convert() loop +// GROVE_FHIR_BENCH_ONLY=name run only the scenario with this name ("concurrent", or "workout-diagnose") +// GROVE_FHIR_BENCH_OUT=path also append the result lines to this file +// GROVE_FHIR_BENCH_DUMP=dir write each scenario's first Bundle JSON there and report per-entry sizes +// GROVE_FHIR_BENCH_PROFILE=convert|graph-init loop one phase (deployment heart rate) for an external profiler +// GROVE_FHIR_BENCH_PROFILE_SECONDS=20 how long that loop runs +// +// The scenario names (heartRate-minimal, heartRate-deployment-watch, heartRate-deployment-recordingDevice, +// stepCount-minimal, stepCount-deployment, workout-noEvents-deployment, workout12segments-deployment, +// concurrent-heartRate-deployment-watch) and the result-line format are fixed so runs stay comparable. +// swiftlint:disable force_unwrapping + +#if canImport(HealthKit) + +import Foundation +@testable import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit +import ModelsR4 +import Testing + + +/// The measured state of one scenario, carried from phase to phase. +private struct ScenarioRun { + let scenario: Scenario + let scope: BenchScope + let report: BenchReport + let converter = HealthKitConverter() + var contexts: [HealthKitConversionContext] = [] + var conversions: [HealthKitConversionSet] = [] + var encoded: [Data] = [] + var bestConvertSeconds = 0.0 + var encodeSeconds = 0.0 + var graphInitSeconds = 0.0 + + var samples: [HKSample] { scenario.samples } + var count: Int { scenario.samples.count } + var name: String { scenario.name } + + func rate(_ seconds: Double, _ items: Int? = nil) -> String { + let items = Double(items ?? count) + return String(format: "%.3fs %.1f/s %.1fus/sample", seconds, items / seconds, seconds / items * 1_000_000) + } + + func convert(_ index: Int) throws -> HealthKitConversionSet { + try autoreleasepool { try converter.convert(samples[index], context: contexts[index]) } + } +} + + +@Suite(.serialized, .enabled(if: BenchEnvironment.isEnabled)) +struct ConversionThroughputBenchmark { + private static let warmUpCount = 200 + + private static func scenarios(count: Int) -> [Scenario] { + [ + Scenario(name: "heartRate-minimal", style: .minimal, samples: SampleFactory.heartRate(count: count, device: nil, metadata: nil)), + Scenario( + name: "heartRate-deployment-watch", + style: .deployment, + samples: SampleFactory.heartRate( + count: count, + device: SampleFactory.watchWithoutUnitToken, + metadata: [HKMetadataKeyHeartRateMotionContext: NSNumber(value: 1)] + ) + ), + Scenario( + name: "heartRate-deployment-recordingDevice", + style: .deployment, + samples: SampleFactory.heartRate( + count: count, + device: SampleFactory.deviceWithUnitToken, + metadata: [HKMetadataKeyHeartRateMotionContext: NSNumber(value: 1), HKMetadataKeyTimeZone: "America/Los_Angeles"] + ) + ), + Scenario(name: "stepCount-minimal", style: .minimal, samples: SampleFactory.stepCount(count: count)), + Scenario(name: "stepCount-deployment", style: .deployment, samples: SampleFactory.stepCount(count: count)), + Scenario( + name: "workout-noEvents-deployment", + style: .deployment, + samples: SampleFactory.workouts(count: max(100, count / 10), withEvents: false) + ), + Scenario( + name: "workout12segments-deployment", + style: .deployment, + samples: SampleFactory.workouts(count: max(100, count / 10), withEvents: true) + ) + ] + } + + @Test(.enabled(if: BenchEnvironment.only != "workout-diagnose")) + func baselineThroughput() throws { + let report = BenchReport() + defer { report.flush() } + let count = BenchEnvironment.sampleCount + #if DEBUG + let configuration = "debug" + #else + let configuration = "release" + #endif + let start = Memory.footprint() + report.line("config build=\(configuration) N=\(count) runs=\(BenchEnvironment.runs) cores=\(ProcessInfo.processInfo.activeProcessorCount) " + + "os=\(ProcessInfo.processInfo.operatingSystemVersionString) footprintMB=\(Memory.megabytes(start.current))") + + let scope = BenchScope() + if let phase = BenchEnvironment.profile { + try runProfileLoop(phase: phase, scope: scope, report: report) + return + } + for scenario in Self.scenarios(count: count) where BenchEnvironment.only == nil || BenchEnvironment.only == scenario.name { + var run = ScenarioRun(scenario: scenario, scope: scope, report: report) + guard try warmUp(&run) else { + continue + } + try measureConvert(&run) + try measureEncode(&run) + #if !GROVE_BENCH_NO_PASS_TIMING + try measureValidationPasses(run) + #endif + try measureFoundationWork(run) + try measureConstruction(run) + } + if BenchEnvironment.only == nil || BenchEnvironment.only == "concurrent" { + try runConcurrent(scope: scope, count: count, report: report) + } + let end = Memory.footprint() + report.line("done footprintMB=\(Memory.megabytes(end.current)) lifetimePeakMB=\(Memory.megabytes(end.peak))") + } + + /// Why the converter refuses a synthetic workout: prints the claims the validator compares. + @Test(.enabled(if: BenchEnvironment.only == "workout-diagnose")) + func workoutDiagnose() throws { + let scope = BenchScope() + for withEvents in [false, true] { + let sample = SampleFactory.workouts(count: 1, withEvents: withEvents)[0] + let context = scope.context(for: sample, sequence: 1, style: .deployment) + let type = try #require(HealthKitSourceType(sample)) + let output = try #require(HealthKitCatalog.primaryOutput(for: type)) + let binding = try #require(HealthKitCatalog.binding(for: sample)) + let envelope = try HealthKitConverter.graphEnvelope( + for: sample, context: context, outputRole: output.role, outputDiscriminator: output.discriminator + ) + let observation = try HealthKitConverter.observation(for: sample, binding: binding, graphContext: envelope.graphContext) + let profiles = ExchangeGraph.canonicalStrings(observation.meta?.profile ?? []) + let admitted = Set(ExchangeGraph.canonicalStrings( + ProfileClaims.adapterProvenanceTargetProfiles[HealthKitContract.conversionProvenanceProfile.value!.url.absoluteString] ?? [] + )) + print("BENCH diagnose withEvents=\(withEvents) type=\(type.rawValue) role=\(output.role)/\(output.discriminator) " + + "primaryProfiles=\(profiles) admittedCount=\(admitted.count) primaryAdmitted=\(!admitted.isDisjoint(with: profiles))") + let workout = try #require(sample as? HKWorkout) + let segments = try HealthKitConverter.workoutSegments(workout, envelope: envelope) + for segment in segments.prefix(1) { + let segmentProfiles = ExchangeGraph.canonicalStrings(segment.observation.meta?.profile ?? []) + print("BENCH diagnose segments=\(segments.count) segmentProfiles=\(segmentProfiles) " + + "segmentAdmitted=\(!admitted.isDisjoint(with: segmentProfiles))") + } + do { + _ = try HealthKitConverter().convert(sample, context: context) + print("BENCH diagnose withEvents=\(withEvents) convert=OK") + } catch { + print("BENCH diagnose withEvents=\(withEvents) convert=REFUSED \(error)") + } + } + } + + /// First-use costs (catalog statics, Foundation coder caches) are reported, not averaged in. Returns false + /// when the converter refuses the scenario's input, after reporting what a refusal costs. + private func warmUp(_ run: inout ScenarioRun) throws -> Bool { + let firstContext = run.scope.context(for: run.samples[0], sequence: 1, style: run.scenario.style) + do { + _ = try autoreleasepool { try run.converter.convert(run.samples[0], context: firstContext) } + } catch { + let refusalSeconds = Stopwatch.seconds { + for (index, sample) in run.samples.enumerated() { + let context = run.scope.context(for: sample, sequence: UInt64(index + 1), style: run.scenario.style) + _ = autoreleasepool { try? run.converter.convert(sample, context: context) } + } + } + let diagnostic = (error as? HealthKitConversionError)?.diagnostic + run.report.line("scenario=\(run.name) N=\(run.count) REFUSED error=\(diagnostic?.code ?? String(describing: error)) " + + "at \(diagnostic?.location ?? "?") phase=refusal \(run.rate(refusalSeconds))") + return false + } + let secondContext = run.scope.context(for: run.samples[1], sequence: 2, style: run.scenario.style) + let coldSeconds = try Stopwatch.seconds { + _ = try autoreleasepool { try run.converter.convert(run.samples[1], context: secondContext) } + } + for index in 0.. after.current ? retained.current - after.current : 0 + run.report.line("scenario=\(run.name) phase=convert-total(retained) \(run.rate(retainedSeconds)) " + + "footprintMB=\(Memory.megabytes(retained.current)) retainedKBPerConversion=\(retainedBytes / UInt64(run.count) / 1_024)") + } + + /// (b) JSONEncoder().encode(bundle) alone, the staging re-encode, and the exact production tail of convert(). + private func measureEncode(_ run: inout ScenarioRun) throws { + var encoded: [Data] = [] + encoded.reserveCapacity(run.count) + run.encodeSeconds = try Stopwatch.seconds { + for conversion in run.conversions { + encoded.append(try autoreleasepool { try JSONEncoder().encode(conversion.bundle) }) + } + } + run.encoded = encoded + let bytes = encoded.reduce(0) { $0 + $1.count } + let entries = run.conversions.reduce(0) { $0 + ($1.bundle.entry?.count ?? 0) } + let warnings = run.conversions.reduce(0) { $0 + $1.warnings.count } + run.report.line("scenario=\(run.name) phase=encode-bundle \(run.rate(run.encodeSeconds)) bytesPerBundle=\(bytes / run.count) " + + "entriesPerBundle=\(String(format: "%.1f", Double(entries) / Double(run.count))) " + + "warningsPerSample=\(String(format: "%.2f", Double(warnings) / Double(run.count)))") + if let directory = BenchEnvironment.dumpDirectory { + // The first graph's validated bytes, plus the size of each entry's resource, for inspecting what an event carries. + try encoded[0].write(to: URL(fileURLWithPath: directory).appendingPathComponent("\(run.name).json")) + let sizes = try (run.conversions[0].bundle.entry ?? []).map { entry in + "\(entry.resource?.resourceType ?? "?")=\(try JSONEncoder().encode(entry).count)" + } + run.report.line("scenario=\(run.name) entry-bytes \(sizes.joined(separator: " "))") + } + // What MyHeartCounts stages today: a second encode with sorted keys and unescaped slashes. + let stagingEncoder = JSONEncoder() + stagingEncoder.outputFormatting = [.sortedKeys, .withoutEscapingSlashes] + var stagedBytes = 0 + let stagedSeconds = try Stopwatch.seconds { + for conversion in run.conversions { + stagedBytes += try autoreleasepool { try stagingEncoder.encode(conversion.bundle).count } + } + } + run.report.line("scenario=\(run.name) phase=encode-bundle(sortedKeys+withoutEscapingSlashes) \(run.rate(stagedSeconds)) " + + "bytesPerBundle=\(stagedBytes / run.count)") + // The graph's stored bytes are the encoder's bytes, so (b) is exactly what the graph already holds. + #expect(run.conversions[0].graph.jsonData.count == encoded[0].count) + + run.graphInitSeconds = try Stopwatch.seconds { + for conversion in run.conversions { + _ = try ExchangeGraph(kind: .active, eventIdentifier: conversion.graph.eventIdentifier, bundle: conversion.bundle) + } + } + run.report.line("scenario=\(run.name) phase=graph-init(encode+parse+validate) \(run.rate(run.graphInitSeconds))") + } + + #if !GROVE_BENCH_NO_PASS_TIMING + /// The validation passes in production order. Each graph gets a fresh document, and later passes reuse the + /// identifier caches the earlier ones filled, exactly as ExchangeGraph.validate does. + private func measureValidationPasses(_ run: ScenarioRun) throws { + let passNames = [ + "document(JSONSerialization+entry-map)", "entry-resource-policy", "entry-node-digests", "resource-identifiers", + "identifier-system-roles", "entry-keys", "governed-reference-targets", "active-lifecycle" + ] + var passNanoseconds = [UInt64](repeating: 0, count: passNames.count) + for (conversion, data) in zip(run.conversions, run.encoded) { + try autoreleasepool { + let bundle = conversion.bundle + let entries = bundle.entry ?? [] + var mark = DispatchTime.now().uptimeNanoseconds + func lap(_ pass: Int) { + let now = DispatchTime.now().uptimeNanoseconds + passNanoseconds[pass] += now - mark + mark = now + } + let document = ExchangeGraph.ValidationDocument(bundle: bundle, jsonData: data) + lap(0) + try ExchangeGraph.validateEntryResourcePolicy(kind: .active, entries: entries, document: document) + lap(1) + try ExchangeGraph.validateEntryNodeDigests(entries: entries, eventIdentifier: conversion.graph.eventIdentifier) + lap(2) + try ExchangeGraph.validateResourceIdentifiers(entries: entries, document: document) + lap(3) + try ExchangeIdentity.validateIdentifierSystemRoles(inBundleJSON: document.bundleObject()) + lap(4) + try ExchangeGraph.validateEntryKeys(entries: entries, document: document) + lap(5) + try ExchangeGraph.validateGovernedReferenceTargets(entries: entries, document: document) + lap(6) + try ExchangeGraph.validateActive(entries: entries, document: document) + lap(7) + } + } + let passTotal = passNanoseconds.reduce(0, +) + let perPass = zip(passNames, passNanoseconds).map { name, nanoseconds in + "\(name)=\(String(format: "%.1f", Double(nanoseconds) / Double(run.count) / 1_000))us" + } + run.report.line("scenario=\(run.name) validation-passes total=\(String(format: "%.1f", Double(passTotal) / Double(run.count) / 1_000))us/sample: " + + perPass.joined(separator: " ")) + } + #endif + + /// (c) Re-validation of serialized bytes alone, and the pieces of validation that are pure Foundation work. + private func measureFoundationWork(_ run: ScenarioRun) throws { + let revalidateSeconds = try Stopwatch.seconds { + for data in run.encoded { + _ = try ExchangeGraph(kind: .active, jsonData: data) + } + } + run.report.line("scenario=\(run.name) phase=revalidate-jsonData \(run.rate(revalidateSeconds))") + let parseSeconds = try Stopwatch.seconds { + for data in run.encoded { + _ = try autoreleasepool { try JSONSerialization.jsonObject(with: data) } + } + } + run.report.line("scenario=\(run.name) phase=JSONSerialization-parse \(run.rate(parseSeconds))") + let decodeSeconds = try Stopwatch.seconds { + for data in run.encoded { + _ = try autoreleasepool { try JSONDecoder().decode(ModelsR4.Bundle.self, from: data) } + } + } + run.report.line("scenario=\(run.name) phase=JSONDecoder-decode-bundle \(run.rate(decodeSeconds))") + } + + /// Construction pieces: identities + device snapshots + study context, then the clinical content alone. + private func measureConstruction(_ run: ScenarioRun) throws { + var envelopes: [HealthKitConverter.GraphEnvelope] = [] + envelopes.reserveCapacity(run.count) + let type = HealthKitSourceType(run.samples[0])! + let output = HealthKitCatalog.primaryOutput(for: type)! + let envelopeSeconds = try Stopwatch.seconds { + for index in 0.. String { + String(format: "%.1f%%", seconds / run.bestConvertSeconds * 100) + } + func perSample(_ seconds: Double) -> String { + String(format: "%.1f", seconds / Double(run.count) * 1_000_000) + } + run.report.line("scenario=\(run.name) breakdown-of-convert(best): construction=\(share(construction)) " + + "encode=\(share(run.encodeSeconds)) parse+validate=\(share(validateOnly)) " + + "[usPerSample construction=\(perSample(construction)) encode=\(perSample(run.encodeSeconds)) parse+validate=\(perSample(validateOnly))]") + } + + /// Loops one phase over the deployment heart-rate workload so `sample`/Instruments can attach by pid. + private func runProfileLoop(phase: String, scope: BenchScope, report: BenchReport) throws { + let samples = SampleFactory.heartRate( + count: 1_000, + device: SampleFactory.watchWithoutUnitToken, + metadata: [HKMetadataKeyHeartRateMotionContext: NSNumber(value: 1)] + ) + let contexts = samples.enumerated().map { index, sample in + scope.context(for: sample, sequence: UInt64(index + 1), style: .deployment) + } + let converter = HealthKitConverter() + let conversions = try zip(samples, contexts).map { try converter.convert($0, context: $1) } + report.line("profile phase=\(phase) pid=\(ProcessInfo.processInfo.processIdentifier) seconds=\(BenchEnvironment.profileSeconds)") + let deadline = Date().addingTimeInterval(BenchEnvironment.profileSeconds) + var iterations = 0 + while Date() < deadline { + for index in samples.indices { + try autoreleasepool { + if phase == "graph-init" { + _ = try ExchangeGraph( + kind: .active, + eventIdentifier: conversions[index].graph.eventIdentifier, + bundle: conversions[index].bundle + ) + } else { + _ = try converter.convert(samples[index], context: contexts[index]) + } + } + } + iterations += samples.count + } + report.line("profile phase=\(phase) iterations=\(iterations)") + } + + /// Whether the converter scales across threads: the same deployment heart-rate workload split over T threads. + private func runConcurrent(scope: BenchScope, count: Int, report: BenchReport) throws { + let samples = SampleFactory.heartRate( + count: count, + device: SampleFactory.watchWithoutUnitToken, + metadata: [HKMetadataKeyHeartRateMotionContext: NSNumber(value: 1)] + ) + let contexts = samples.enumerated().map { index, sample in + scope.context(for: sample, sequence: UInt64(index + 1), style: .deployment) + } + let converter = HealthKitConverter() + for threads in [1, 2, 4, 6, 8] { + let failures = ManagedFailureCount() + let seconds = Stopwatch.seconds { + DispatchQueue.concurrentPerform(iterations: threads) { thread in + var index = thread + while index < count { + do { + _ = try autoreleasepool { try converter.convert(samples[index], context: contexts[index]) } + } catch { + failures.increment() + } + index += threads + } + } + } + #expect(failures.value == 0) + report.line("scenario=concurrent-heartRate-deployment-watch threads=\(threads) N=\(count) " + + String(format: "%.3fs %.1f/s", seconds, Double(count) / seconds)) + } + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift new file mode 100644 index 000000000..41e83db67 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift @@ -0,0 +1,247 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import CoreLocation +import Foundation +import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit +import ModelsR4 + + +enum GoldenCaseError: Error { + case unexpectedCompanions(Int) + case routeOmitted + case unknownTimeZone(String) + case workoutNotBuilt +} + + +/// The ECG, recording-document and retraction shapes the goldens pin. +extension GoldenCase { + /// Sequences 60-79: graphs whose source has no public initializer, built on stored-sample fixtures. + /// + /// The ECG goes through `HealthKitConverter.convertECG(_:evidence:symptoms:context:symptomContexts:)`, the + /// internal seam below the public entry point, because the evidence an `HKElectrocardiogram` reports lives in + /// private storage the fixtures do not write; the envelope sample is a real `HKElectrocardiogram` nonetheless. + static let documents: [GoldenCase] = [ + GoldenCase("electrocardiogram", sequence: 60) { sequence in + GoldenOutput(try electrocardiogram(uuid: 60, sequence: sequence, symptom: nil).primary) + }, + GoldenCase("electrocardiogram-with-symptom", sequence: 61) { sequence in + GoldenOutput(try electrocardiogram(uuid: 61, sequence: sequence, symptom: GoldenFixtures.uuid(0x61)).primary) + }, + GoldenCase("electrocardiogram-symptom-companion", sequence: 61) { sequence in + let companions = try electrocardiogram(uuid: 61, sequence: sequence, symptom: GoldenFixtures.uuid(0x61)).companions + guard companions.count == 1, let companion = companions.first else { + throw GoldenCaseError.unexpectedCompanions(companions.count) + } + return GoldenOutput(companion) + }, + GoldenCase("heartbeat-series", sequence: 62) { sequence in + let series = try StoredSampleFixtures.seriesSample( + HKHeartbeatSeriesSample.self, + sampleType: HKSeriesType.heartbeat(), + shape: seriesShape(uuid: 62, duration: 2) + ) + let record = HealthKitHeartbeatSeriesRecord(series: series, heartbeats: [ + HealthKitHeartbeat(timeSinceSeriesStart: 0, precededByGap: false), + HealthKitHeartbeat(timeSinceSeriesStart: 0.84, precededByGap: false), + HealthKitHeartbeat(timeSinceSeriesStart: 1.71, precededByGap: true) + ]) + return GoldenOutput(try HealthKitConverter().convert(record, context: GoldenFixtures.context(sequence: sequence)).primary) + }, + GoldenCase("workout-route", sequence: 63) { sequence in + let route = try StoredSampleFixtures.seriesSample( + HKWorkoutRoute.self, + sampleType: HKSeriesType.workoutRoute(), + shape: seriesShape(uuid: 63, duration: 1) + ) + var inputs = GoldenFixtures.Inputs() + inputs.options.routeDisclosure = .authorized + let record = HealthKitWorkoutRouteRecord(route: route, locations: routeLocations) + guard let conversion = try HealthKitConverter().convert(record, context: GoldenFixtures.context(sequence: sequence, inputs)) else { + throw GoldenCaseError.routeOmitted + } + return GoldenOutput(conversion.primary) + } + ] + clinicalDocuments + + /// Sequences 80-99: retractions of deleted records. + static let retractions: [GoldenCase] = [ + GoldenCase("retraction-heart-rate", sequence: 80) { sequence in + GoldenOutput(try HealthKitConverter().retraction( + for: HealthKitSourceRecord(uuid: GoldenFixtures.uuid(80), type: .heartRate), + context: GoldenFixtures.context(sequence: sequence), + occurred: .instant(GoldenFixtures.conversionInstant) + )) + }, + GoldenCase("retraction-heart-rate-native-identifier", sequence: 81) { sequence in + var inputs = GoldenFixtures.Inputs() + inputs.options.nativeIdentifierDisclosure = .authorized(system: GoldenFixtures.nativeIdentifierSystem) + return GoldenOutput(try HealthKitConverter().retraction( + for: HealthKitSourceRecord(uuid: GoldenFixtures.uuid(81), type: .heartRate), + context: GoldenFixtures.context(sequence: sequence, inputs), + occurred: .period(start: GoldenFixtures.sampleStart, end: GoldenFixtures.conversionInstant) + )) + }, + GoldenCase("retraction-electrocardiogram", sequence: 82) { sequence in + GoldenOutput(try HealthKitConverter().retraction( + for: HealthKitSourceRecord(uuid: GoldenFixtures.uuid(82), type: .electrocardiogram), + context: GoldenFixtures.context(sequence: sequence), + occurred: .instant(GoldenFixtures.conversionInstant) + )) + }, + GoldenCase("retraction-blood-pressure", sequence: 83) { sequence in + GoldenOutput(try HealthKitConverter().retraction( + for: HealthKitSourceRecord(uuid: GoldenFixtures.uuid(83), type: .bloodPressure), + context: GoldenFixtures.context(sequence: sequence), + occurred: .period(start: nil, end: GoldenFixtures.conversionInstant) + )) + } + ] + + #if os(watchOS) + static let clinicalDocuments: [GoldenCase] = [] + #else + /// `HKCDADocumentSample` has a public initializer, but no watchOS. + static let clinicalDocuments: [GoldenCase] = [ + GoldenCase("clinical-document", sequence: 64) { sequence in + let document = try HKCDADocumentSample( + data: Data(clinicalDocumentXML.utf8), + start: GoldenFixtures.sampleStart, + end: GoldenFixtures.sampleStart.addingTimeInterval(1), + metadata: GoldenFixtures.timeZoneMetadata + ) + return try GoldenFixtures.convert(StoredSampleFixtures.stored(document, uuid: GoldenFixtures.uuid(64)), sequence: sequence) + } + ] + #endif + + /// Two fixes one second apart; the second one reports no vertical accuracy, course or speed. + static let routeLocations = [ + CLLocation( + coordinate: CLLocationCoordinate2D(latitude: 37.4275, longitude: -122.1697), + altitude: 30.5, + horizontalAccuracy: 5, + verticalAccuracy: 3, + course: 91.5, + courseAccuracy: 10, + speed: 2.25, + speedAccuracy: 0.5, + timestamp: GoldenFixtures.sampleStart + ), + CLLocation( + coordinate: CLLocationCoordinate2D(latitude: 37.4276, longitude: -122.1698), + altitude: 0, + horizontalAccuracy: 65, + verticalAccuracy: -1, + course: -1, + courseAccuracy: -1, + speed: -1, + speedAccuracy: -1, + timestamp: GoldenFixtures.sampleStart.addingTimeInterval(1) + ) + ] + + static let clinicalDocumentXML = """ + + + + + + Grove Golden Summary + + + + \ + ExampleParticipant + + \ + Example Hospital\ + +
NotesExample.
\ +
+
+ """ + + /// The sinus-rhythm ECG the conformance fixtures use, converted with or without one correlated symptom. + /// + /// The symptom's own event takes `sequence + 100`, the only second sequence any case states. + static func electrocardiogram(uuid ordinal: UInt8, sequence: UInt64, symptom: UUID?) throws -> HealthKitConversionSet { + let ecg = try StoredSampleFixtures.seriesSample( + HKElectrocardiogram.self, + sampleType: HKObjectType.electrocardiogramType(), + shape: seriesShape(uuid: ordinal, duration: 30) + ) + guard let timeZone = TimeZone(identifier: GoldenFixtures.timeZone) else { + throw GoldenCaseError.unknownTimeZone(GoldenFixtures.timeZone) + } + let source = HealthKitECGSourceEvidence( + sourceTypeIdentifier: HealthKitContract.electrocardiogramSourceTypeIdentifier, + startDate: GoldenFixtures.sampleStart, + endDate: GoldenFixtures.sampleStart.addingTimeInterval(30), + timeZone: timeZone, + classification: .sinusRhythm, + symptomsStatus: symptom == nil ? .none : .present, + numberOfVoltageMeasurements: 4, + averageHeartRate: 72, + samplingFrequency: 500, + algorithmVersion: HKAppleECGAlgorithmVersion.version2.rawValue, + wasUserEntered: false + ) + let waveform = try HealthKitECGEvidenceValidator.validateWaveform( + reportedCount: source.numberOfVoltageMeasurements, + samplingFrequencyHertz: source.samplingFrequency, + points: [ + HealthKitECGVoltagePoint(timeSinceSampleStart: 0.250, millivolts: 0.125), + HealthKitECGVoltagePoint(timeSinceSampleStart: 0.252, millivolts: 0.250), + HealthKitECGVoltagePoint(timeSinceSampleStart: 0.254, millivolts: -0.125), + HealthKitECGVoltagePoint(timeSinceSampleStart: 0.256, millivolts: 0) + ] + ) + var symptoms: [HKCategorySample] = [] + var symptomContexts: [HealthKitConversionContext] = [] + if let symptom { + let sample = HKCategorySample( + type: HKCategoryType(.chestTightnessOrPain), + value: HKCategoryValueSeverity.mild.rawValue, + start: GoldenFixtures.sampleStart, + end: GoldenFixtures.sampleStart.addingTimeInterval(30), + device: GoldenFixtures.watch, + metadata: GoldenFixtures.timeZoneMetadata + ) + symptoms = [try StoredSampleFixtures.stored(sample, uuid: symptom, writer: GoldenFixtures.foreignWriter)] + symptomContexts = [try GoldenFixtures.context(sequence: sequence + 100)] + } + return try HealthKitConverter.convertECG( + ecg, + evidence: HealthKitECGEvidence(source: source, waveform: waveform), + symptoms: symptoms, + context: GoldenFixtures.context(sequence: sequence), + symptomContexts: symptomContexts + ) + } + + /// A series recorded by the watch, written by the foreign application. + static func seriesShape(uuid ordinal: UInt8, duration: TimeInterval) -> StoredSampleFixtures.SeriesShape { + StoredSampleFixtures.SeriesShape( + uuid: GoldenFixtures.uuid(ordinal), + start: GoldenFixtures.sampleStart, + end: GoldenFixtures.sampleStart.addingTimeInterval(duration), + device: GoldenFixtures.watch, + metadata: GoldenFixtures.timeZoneMetadata, + writer: GoldenFixtures.foreignWriter + ) + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift new file mode 100644 index 000000000..056187f4e --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift @@ -0,0 +1,248 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit +import ModelsR4 + + +/// The Observation-graph shapes the goldens pin: one sample each, converted through `HealthKitConverter.convert(_:context:)`. +extension GoldenCase { + /// Every pinned shape, in the order the goldens directory lists them. + static let all: [GoldenCase] = observations + writers + disclosures + documents + retractions + + /// Sequences 1-19: the measurement shapes under the default context. + static let observations: [GoldenCase] = [ + GoldenCase("heart-rate-minimal", sequence: 1) { sequence in + try GoldenFixtures.convert( + GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(1), metadata: nil, writer: .unattributed), + sequence: sequence + ) + }, + GoldenCase("heart-rate-study", sequence: 2) { sequence in + var inputs = GoldenFixtures.Inputs() + inputs.studies = [.test("study-a")] + return try GoldenFixtures.convert(GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(2)), sequence: sequence, inputs) + }, + GoldenCase("heart-rate-recording-device", sequence: 3) { sequence in + try GoldenFixtures.convert(GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(3), device: GoldenFixtures.watch), sequence: sequence) + }, + GoldenCase("heart-rate-device-without-unit-token", sequence: 4) { sequence in + try GoldenFixtures.convert( + GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(4), device: GoldenFixtures.watchWithoutUnitToken), + sequence: sequence + ) + }, + GoldenCase("heart-rate-no-time-zone", sequence: 5) { sequence in + try GoldenFixtures.convert( + GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(5), device: GoldenFixtures.watch, metadata: nil), + sequence: sequence + ) + }, + GoldenCase("heart-rate-interval", sequence: 6) { sequence in + try GoldenFixtures.convert( + GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(6), end: GoldenFixtures.sampleStart.addingTimeInterval(45)), + sequence: sequence + ) + }, + GoldenCase("heart-rate-motion-context", sequence: 7) { sequence in + let metadata: [String: any Sendable] = [ + HKMetadataKeyTimeZone: GoldenFixtures.timeZone, + HKMetadataKeyHeartRateMotionContext: HKHeartRateMotionContext.active.rawValue + ] + return try GoldenFixtures.convert( + GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(7), device: GoldenFixtures.watch, metadata: metadata), + sequence: sequence + ) + }, + GoldenCase("step-count-period", sequence: 8) { sequence in + let steps = HKQuantitySample( + type: HKQuantityType(.stepCount), + quantity: HKQuantity(unit: .count(), doubleValue: 120), + start: GoldenFixtures.sampleStart, + end: GoldenFixtures.sampleStart.addingTimeInterval(60), + device: GoldenFixtures.watch, + metadata: GoldenFixtures.timeZoneMetadata + ) + return try GoldenFixtures.convert(StoredSampleFixtures.stored(steps, uuid: GoldenFixtures.uuid(8)), sequence: sequence) + }, + GoldenCase("blood-pressure-correlation", sequence: 9) { sequence in + try GoldenFixtures.convert(bloodPressure(), sequence: sequence) + }, + GoldenCase("sleep-analysis", sequence: 10) { sequence in + try GoldenFixtures.convert( + GoldenFixtures.category(.sleepAnalysis, value: HKCategoryValueSleepAnalysis.asleepCore.rawValue, uuid: GoldenFixtures.uuid(10), duration: 3_600), + sequence: sequence + ) + }, + GoldenCase("state-of-mind", sequence: 11) { sequence in + let stateOfMind = HKStateOfMind( + date: GoldenFixtures.sampleStart, + kind: .momentaryEmotion, + valence: 0.5, + labels: [.happy], + associations: [.work], + metadata: GoldenFixtures.timeZoneMetadata + ) + return try GoldenFixtures.convert(StoredSampleFixtures.stored(stateOfMind, uuid: GoldenFixtures.uuid(11)), sequence: sequence) + }, + GoldenCase("insulin-delivery-bolus", sequence: 12) { sequence in + let metadata: [String: any Sendable] = [ + HKMetadataKeyTimeZone: GoldenFixtures.timeZone, + HKMetadataKeyInsulinDeliveryReason: HKInsulinDeliveryReason.bolus.rawValue + ] + return try GoldenFixtures.convert( + GoldenFixtures.quantity(.insulinDelivery, HKQuantity(unit: .internationalUnit(), doubleValue: 2.5), uuid: GoldenFixtures.uuid(12), metadata: metadata), + sequence: sequence + ) + }, + GoldenCase("body-mass-user-entered", sequence: 13) { sequence in + let metadata: [String: any Sendable] = [HKMetadataKeyTimeZone: GoldenFixtures.timeZone, HKMetadataKeyWasUserEntered: true] + return try GoldenFixtures.convert( + GoldenFixtures.quantity(.bodyMass, HKQuantity(unit: .gramUnit(with: .kilo), doubleValue: 71.3), uuid: GoldenFixtures.uuid(13), metadata: metadata), + sequence: sequence + ) + } + ] + + /// Sequences 20-39: how the sample's writer (`HKSourceRevision`) travels. + static let writers: [GoldenCase] = [ + GoldenCase("writer-foreign-application", sequence: 20) { sequence in + try GoldenFixtures.convert(attributedHeartRate(uuid: 20, writer: GoldenFixtures.foreignWriter), sequence: sequence) + }, + // The converter states version 1.2.3 build 42 and HealthKit records revision version 42: the shape a real + // device produces. The tokens differ, so the writer travels as a second application Device of the same bundle. + GoldenCase("writer-self-build-equals-revision", sequence: 21) { sequence in + var inputs = GoldenFixtures.Inputs() + inputs.converter = GoldenFixtures.selfConverter(version: "1.2.3", build: "42") + return try GoldenFixtures.convert(attributedHeartRate(uuid: 21, writer: GoldenFixtures.selfWriter(revisionVersion: "42")), sequence: sequence, inputs) + }, + GoldenCase("writer-self-older-build", sequence: 22) { sequence in + var inputs = GoldenFixtures.Inputs() + inputs.converter = GoldenFixtures.selfConverter(version: "1.2.3", build: "43") + return try GoldenFixtures.convert(attributedHeartRate(uuid: 22, writer: GoldenFixtures.selfWriter(revisionVersion: "42")), sequence: sequence, inputs) + }, + // No build and a version equal to the revision's: the only shape whose writer token equals the converter's. + GoldenCase("writer-self-token-identical", sequence: 23) { sequence in + var inputs = GoldenFixtures.Inputs() + inputs.converter = GoldenFixtures.selfConverter(version: "42", build: nil) + return try GoldenFixtures.convert(attributedHeartRate(uuid: 23, writer: GoldenFixtures.selfWriter(revisionVersion: "42")), sequence: sequence, inputs) + }, + GoldenCase("writer-host-equals-converter-host", sequence: 24) { sequence in + var inputs = GoldenFixtures.Inputs() + inputs.converterHost = try HostDevice(operatingSystemVersion: "26.1.0", name: "Phone", manufacturer: "Apple", modelNumber: "iPhone17,1") + return try GoldenFixtures.convert(attributedHeartRate(uuid: 24, writer: GoldenFixtures.foreignWriter), sequence: sequence, inputs) + }, + GoldenCase("writer-device-classification", sequence: 25) { sequence in + var inputs = GoldenFixtures.Inputs() + inputs.options.writer = .device + return try GoldenFixtures.convert(attributedHeartRate(uuid: 25, writer: GoldenFixtures.foreignWriter), sequence: sequence, inputs) + }, + GoldenCase("writer-device-classification-without-recording-device", sequence: 26) { sequence in + var inputs = GoldenFixtures.Inputs() + inputs.options.writer = .device + return try GoldenFixtures.convert( + GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(26), writer: GoldenFixtures.foreignWriter), + sequence: sequence, + inputs + ) + }, + GoldenCase("writer-blank-name-with-sync-identity", sequence: 27) { sequence in + var writer = GoldenFixtures.foreignWriter + writer.name = "" + return try GoldenFixtures.convert(attributedHeartRate(uuid: 27, writer: writer, metadata: syncMetadata), sequence: sequence) + }, + GoldenCase("writer-without-version", sequence: 28) { sequence in + var writer = GoldenFixtures.foreignWriter + writer.version = nil + return try GoldenFixtures.convert(attributedHeartRate(uuid: 28, writer: writer), sequence: sequence) + }, + GoldenCase("sync-identity", sequence: 29) { sequence in + try GoldenFixtures.convert(attributedHeartRate(uuid: 29, writer: GoldenFixtures.foreignWriter, metadata: syncMetadata), sequence: sequence) + } + ] + + /// Sequences 40-59: disclosure policies, converter roles, subjects and studies. + static let disclosures: [GoldenCase] = [ + GoldenCase("native-identifier-disclosure", sequence: 40) { sequence in + var inputs = GoldenFixtures.Inputs() + inputs.options.nativeIdentifierDisclosure = .authorized(system: GoldenFixtures.nativeIdentifierSystem) + return try GoldenFixtures.convert(attributedHeartRate(uuid: 40, writer: GoldenFixtures.foreignWriter), sequence: sequence, inputs) + }, + GoldenCase("udi-disclosure", sequence: 41) { sequence in + var inputs = GoldenFixtures.Inputs() + inputs.options.udiDisclosure = .authorizedUDI + return try GoldenFixtures.convert(attributedHeartRate(uuid: 41, writer: GoldenFixtures.foreignWriter), sequence: sequence, inputs) + }, + GoldenCase("gateway-role", sequence: 42) { sequence in + var inputs = GoldenFixtures.Inputs() + inputs.converterRole = .gateway + return try GoldenFixtures.convert(attributedHeartRate(uuid: 42, writer: GoldenFixtures.foreignWriter), sequence: sequence, inputs) + }, + GoldenCase("gateway-application-role", sequence: 43) { sequence in + var inputs = GoldenFixtures.Inputs() + inputs.converterRole = .gatewayApplication(.test(name: "Cuff Companion", bundleIdentifier: "com.example.cuff", version: "3.1")) + return try GoldenFixtures.convert(attributedHeartRate(uuid: 43, writer: GoldenFixtures.foreignWriter), sequence: sequence, inputs) + }, + GoldenCase("bundled-patient-subject", sequence: 44) { sequence in + var inputs = GoldenFixtures.Inputs() + inputs.subject = .bundled(.test(.patient, "example"), Patient()) + return try GoldenFixtures.convert(attributedHeartRate(uuid: 44, writer: GoldenFixtures.foreignWriter), sequence: sequence, inputs) + }, + GoldenCase("two-study-enrollments", sequence: 45) { sequence in + var inputs = GoldenFixtures.Inputs() + inputs.studies = [.test("study-a"), .test("study-b")] + return try GoldenFixtures.convert(attributedHeartRate(uuid: 45, writer: GoldenFixtures.foreignWriter), sequence: sequence, inputs) + }, + GoldenCase("repository-ids-on-every-node", sequence: 46) { sequence in + var inputs = GoldenFixtures.Inputs() + inputs.repositoryIDs = try Dictionary(uniqueKeysWithValues: [ + (ExchangeGraphNode.bundle, "bundle-46"), (.primaryOutput, "output-46"), (.provenance, "provenance-46"), + (.applicationDevice, "app-46"), (.hostDevice, "host-46"), (.recordingDevice, "recorder-46"), + (.writer, "writer-46"), (.writerHost, "writer-host-46") + ].map { node, id in (node, try RepositoryID(id)) }) + return try GoldenFixtures.convert(attributedHeartRate(uuid: 46, writer: GoldenFixtures.foreignWriter), sequence: sequence, inputs) + } + ] + + static let syncMetadata: [String: any Sendable] = [ + HKMetadataKeyTimeZone: GoldenFixtures.timeZone, + HKMetadataKeySyncIdentifier: "sync-abc", + HKMetadataKeySyncVersion: 3 + ] + + /// A heart rate from the watch, written by `writer`. + static func attributedHeartRate( + uuid ordinal: UInt8, + writer: StoredSampleFixtures.Writer, + metadata: [String: any Sendable] = GoldenFixtures.timeZoneMetadata + ) throws -> HKQuantitySample { + try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(ordinal), device: GoldenFixtures.watch, metadata: metadata, writer: writer) + } + + static func bloodPressure() throws -> HKCorrelation { + func component(_ type: HKQuantityTypeIdentifier, _ value: Double, uuid: UInt8) throws -> HKQuantitySample { + try GoldenFixtures.quantity(type, HKQuantity(unit: .millimeterOfMercury(), doubleValue: value), uuid: GoldenFixtures.uuid(uuid), device: GoldenFixtures.watch) + } + let correlation = HKCorrelation( + type: HKCorrelationType(.bloodPressure), + start: GoldenFixtures.sampleStart, + end: GoldenFixtures.sampleStart, + objects: [try component(.bloodPressureSystolic, 120, uuid: 0x91), try component(.bloodPressureDiastolic, 80, uuid: 0x92)], + device: GoldenFixtures.watch, + metadata: GoldenFixtures.timeZoneMetadata + ) + return try StoredSampleFixtures.stored(correlation, uuid: GoldenFixtures.uuid(9)) + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift new file mode 100644 index 000000000..d48065f72 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift @@ -0,0 +1,237 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit +import ModelsR4 +import Testing + + +/// What one case pins: the graph the old API emitted and, in order, what it reported losing. +struct GoldenOutput: Sendable { + let graph: ExchangeGraph + let warnings: [HealthKitConversionWarning] + + /// Each warning as the outline spells it: the registry code, then the field, device name or keys it names. + var renderedWarnings: [String] { + warnings.map { warning in + switch warning { + case .recordingDeviceOmitted(let deviceName): + "\(warning.diagnostic.code)(\(deviceName ?? ""))" + case .sourceOffsetUnavailable(let field): + "\(warning.diagnostic.code)@\(field)" + case .unmodeledMetadataWithheld(let keys): + "\(warning.diagnostic.code)(\(keys.joined(separator: ",")))" + } + } + } + + init(_ conversion: HealthKitConversion) { + graph = conversion.graph + warnings = conversion.warnings + } + + init(_ retraction: RetractionEvent) { + graph = retraction.graph + warnings = [] + } +} + + +/// One pinned wire shape: a stable name, the event sequence its context states, and how the +/// converter's public API (or, for ECGs, the internal seam the existing tests use) produces it. +/// +/// Sequences are append-only: a new case takes the next free number of its group so that adding a +/// case never re-mints the identities of an existing golden. +struct GoldenCase: Sendable, CustomTestStringConvertible { + let name: String + let sequence: UInt64 + private let produce: @Sendable (UInt64) throws -> GoldenOutput + + var testDescription: String { name } + + init(_ name: String, sequence: UInt64, produce: @escaping @Sendable (_ sequence: UInt64) throws -> GoldenOutput) { + self.name = name + self.sequence = sequence + self.produce = produce + } + + func output() throws -> GoldenOutput { + try produce(sequence) + } +} + + +/// The fixed inputs every golden case is built from. Nothing here reads the clock, the process +/// or the host, so two runs on two machines mint the same identities and the same bytes. +enum GoldenFixtures { + /// What a case varies beyond its sample: every field defaults to the test context's fixed facts. + struct Inputs: Sendable { + var subject: Subject = .testPatient + var converter: ApplicationDevice = .test + var converterHost: HostDevice = .test + var converterRole: ConverterRole = .assembler + var studies: [StudyEnrollment] = [] + var repositoryIDs: [ExchangeGraphNode: RepositoryID] = [:] + var options = HealthKitConversionOptions() + } + + /// 2026-08-17T23:30:00Z, in whole seconds: the conversion instant of every case. + static let conversionInstant = ExchangeEventContext.testInstant + /// 2026-08-17T22:30:00Z (15:30 in Los Angeles): when every sample starts. + static let sampleStart = Date(timeIntervalSince1970: 1_787_005_800) + static let timeZone = "America/Los_Angeles" + static let nativeIdentifierSystem: IdentifierSystem = "https://study.example.org/fhir/NamingSystem/healthkit-store" + static let beatsPerMinute = HKUnit.count().unitDivided(by: .minute()) + + /// A watch that names its physical unit and carries a UDI, so the recording Device and the UDI disclosure both apply. + static let watch = HKDevice( + name: "Apple Watch", + manufacturer: "Apple Inc.", + model: "Watch7,12", + hardwareVersion: "Watch7,12", + firmwareVersion: "1.0", + softwareVersion: "26.2.1", + localIdentifier: "6C4B1D1E-0000-4000-8000-000000000001", + udiDeviceIdentifier: "(01)00844588003288" + ) + + /// The same watch as HealthKit reports it without a per-unit token: no recording Device, and the omission is reported. + static let watchWithoutUnitToken = HKDevice( + name: "Apple Watch", + manufacturer: "Apple Inc.", + model: "Watch7,12", + hardwareVersion: "Watch7,12", + firmwareVersion: "1.0", + softwareVersion: "26.2.1", + localIdentifier: nil, + udiDeviceIdentifier: nil + ) + + /// A third-party application that wrote the sample on its own phone. + static let foreignWriter = StoredSampleFixtures.Writer( + name: "Example Writer", + bundleIdentifier: "org.example.writer", + version: "42", + productType: "iPhone17,1" + ) + + static let timeZoneMetadata: [String: any Sendable] = [HKMetadataKeyTimeZone: timeZone] + + /// A per-case UUID that reads as one: `3A7E5C10-0000-4000-8000-0000000000NN`. + static func uuid(_ ordinal: UInt8) -> UUID { + UUID(uuid: (0x3A, 0x7E, 0x5C, 0x10, 0x00, 0x00, 0x40, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ordinal)) + } + + /// The context of one case: the test identity scope and key, the fixed producer instance, and `sequence`. + static func context(sequence: UInt64, _ inputs: Inputs = Inputs()) throws -> HealthKitConversionContext { + let base = ExchangeEventContext.test() + let event = try ExchangeEventIdentifier( + system: base.identityScope.systems.event, + producerInstance: base.event.producerInstance, + sequence: EventSequence(sequence) + ) + return HealthKitConversionContext( + event: ExchangeEventContext( + subject: inputs.subject, + event: event, + identityScope: base.identityScope, + repositoryScope: base.repositoryScope, + application: inputs.converter, + host: inputs.converterHost, + conversionInstant: conversionInstant, + converterRole: inputs.converterRole, + studies: inputs.studies, + repositoryIDs: inputs.repositoryIDs + ), + options: inputs.options + ) + } + + /// The primary graph of `sample` under the old public entry point, with what the conversion reported losing. + static func convert(_ sample: HKSample, sequence: UInt64, _ inputs: Inputs = Inputs()) throws -> GoldenOutput { + GoldenOutput(try HealthKitConverter().convert(sample, context: context(sequence: sequence, inputs)).primary) + } + + /// A 72 bpm heart rate; `end` stays the start instant unless a case states an interval. + static func heartRate( + uuid: UUID, + device: HKDevice? = nil, + metadata: [String: any Sendable]? = timeZoneMetadata, // swiftlint:disable:this discouraged_optional_collection + writer: StoredSampleFixtures.Writer? = nil, + end: Date? = nil + ) throws -> HKQuantitySample { + let sample = HKQuantitySample( + type: HKQuantityType(.heartRate), + quantity: HKQuantity(unit: beatsPerMinute, doubleValue: 72), + start: sampleStart, + end: end ?? sampleStart, + device: device, + metadata: metadata + ) + return try StoredSampleFixtures.stored(sample, uuid: uuid, writer: writer) + } + + /// A point-in-time quantity at the sample start, attributed to no writer. + static func quantity( + _ type: HKQuantityTypeIdentifier, + _ quantity: HKQuantity, + uuid: UUID, + device: HKDevice? = nil, + metadata: [String: any Sendable]? = timeZoneMetadata // swiftlint:disable:this discouraged_optional_collection + ) throws -> HKQuantitySample { + let sample = HKQuantitySample( + type: HKQuantityType(type), + quantity: quantity, + start: sampleStart, + end: sampleStart, + device: device, + metadata: metadata + ) + return try StoredSampleFixtures.stored(sample, uuid: uuid) + } + + static func category( + _ type: HKCategoryTypeIdentifier, + value: Int, + uuid: UUID, + duration: TimeInterval, + device: HKDevice? = watch + ) throws -> HKCategorySample { + let sample = HKCategorySample( + type: HKCategoryType(type), + value: value, + start: sampleStart, + end: sampleStart.addingTimeInterval(duration), + device: device, + metadata: timeZoneMetadata + ) + return try StoredSampleFixtures.stored(sample, uuid: uuid) + } + + /// The converter the sample's own writer belongs to: the same bundle identifier, with the version and build given. + static func selfConverter(version: String, build: String?) -> ApplicationDevice { + ApplicationDevice.test(name: "Grove Test", bundleIdentifier: ApplicationDevice.test.bundleIdentifier, version: version, build: build) + } + + /// The sample's writer when the converter wrote it: the converter's bundle identifier, stating `revisionVersion`. + static func selfWriter(revisionVersion: String?) -> StoredSampleFixtures.Writer { + StoredSampleFixtures.Writer( + name: "Grove Test", + bundleIdentifier: ApplicationDevice.test.bundleIdentifier, + version: revisionVersion, + productType: "iPhone17,1" + ) + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift new file mode 100644 index 000000000..3ce446977 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift @@ -0,0 +1,318 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +@testable import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit +import ModelsR4 +import Testing + + +/// Where the checked-in goldens live, and where a regeneration writes. +/// +/// Goldens are regenerated OUTSIDE the checkout: `GROVE_GOLDEN_OUTPUT_DIR` (under `xcodebuild`, pass it as +/// `TEST_RUNNER_GROVE_GOLDEN_OUTPUT_DIR`) names a directory the suite writes every case into, and the files are +/// copied into `Resources/Goldens/` afterwards. Writing into the checkout while Xcode runs the tests makes it +/// re-resolve the package graph mid-run. +private enum GoldenStore { + struct MissingGolden: Error, CustomStringConvertible { + let name: String + + var description: String { + "No golden '\(name).json' is checked in; regenerate with GROVE_GOLDEN_OUTPUT_DIR and copy it into Resources/Goldens" + } + } + + static let subdirectory = "Goldens" + static let outlinesName = "outlines" + + static let outputDirectory: URL? = ProcessInfo.processInfo.environment["GROVE_GOLDEN_OUTPUT_DIR"] + .flatMap { $0.isEmpty ? nil : URL(fileURLWithPath: $0, isDirectory: true) } + + static var isGenerating: Bool { outputDirectory != nil } + + /// Sorted members and no escaped slashes, so a regenerated golden diffs by content; the comparison reads tokens, not text. + static var encoder: JSONEncoder { + let encoder = JSONEncoder() + encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes] + return encoder + } + + /// Every checked-in golden's name, whichever way the build system laid the resources out: `.process` flattens the + /// subdirectory, and a lookup under a subdirectory that is not there answers an empty array, not nil. + static var checkedInNames: Set { + let urls = [subdirectory, nil] + .compactMap { Bundle.module.urls(forResourcesWithExtension: "json", subdirectory: $0) } + .first { !$0.isEmpty } ?? [] + return Set(urls.map { $0.deletingPathExtension().lastPathComponent }) + } + + static func data(named name: String) throws -> Data { + guard let url = Bundle.module.url(forResource: name, withExtension: "json", subdirectory: subdirectory) + ?? Bundle.module.url(forResource: name, withExtension: "json") else { + throw MissingGolden(name: name) + } + return try Data(contentsOf: url) + } + + static func outlines() throws -> [String: GoldenOutline] { + try JSONDecoder().decode([String: GoldenOutline].self, from: data(named: outlinesName)) + } +} + + +/// The parts of an output the refactor is most likely to reorder or drop, pinned on their own so a failure names +/// them: every entry's fullUrl in Bundle order, each resource's identifier and extension arrays in order, and the +/// conversion's warnings in order. +struct GoldenOutline: Codable, Equatable { + struct Entry: Codable, Equatable { + let fullUrl: String + let resourceType: String + /// `||` per identifier, in array order. + let identifiers: [String] + /// Each extension's url, in array order. + let extensions: [String] + } + + let entries: [Entry] + /// `GoldenOutput.renderedWarnings`. + let warnings: [String] + + init(_ bundle: LosslessJSONValue, warnings: [String]) { + self.warnings = warnings + entries = (bundle["entry"]?.elements ?? []).map { entry in + let resource = entry["resource"] + return Entry( + fullUrl: entry["fullUrl"]?.text ?? "", + resourceType: resource?["resourceType"]?.text ?? "", + identifiers: (resource?["identifier"]?.elements ?? []).map { identifier in + let typeCode = identifier["type"]?["coding"]?.elements?.first?["code"]?.text ?? "-" + return "\(typeCode)|\(identifier["system"]?.text ?? "")|\(identifier["value"]?.text ?? "")" + }, + extensions: (resource?["extension"]?.elements ?? []).map { $0["url"]?.text ?? "" } + ) + } + } +} + + +/// Names the first path where two token trees differ. +private enum TokenDiff { + /// The first path where two token trees differ, or nil when they are equal. + static func firstDifference(expected: LosslessJSONValue, actual: LosslessJSONValue, at path: String = "$") -> String? { + switch (expected, actual) { + case let (.object(lhs), .object(rhs)): + for key in Set(lhs.keys).union(rhs.keys).sorted() { + guard let left = lhs[key] else { + return "\(path).\(key): golden has no such member, actual is \(rhs[key].map(describe) ?? "")" + } + guard let right = rhs[key] else { + return "\(path).\(key): missing, golden has \(describe(left))" + } + if let difference = firstDifference(expected: left, actual: right, at: "\(path).\(key)") { + return difference + } + } + return nil + case let (.array(lhs), .array(rhs)): + for (index, pair) in zip(lhs, rhs).enumerated() { + if let difference = firstDifference(expected: pair.0, actual: pair.1, at: "\(path)[\(index)]") { + return difference + } + } + return lhs.count == rhs.count ? nil : "\(path): golden has \(lhs.count) elements, actual has \(rhs.count)" + default: + return expected == actual ? nil : "\(path): golden \(describe(expected)), actual \(describe(actual))" + } + } + + private static func describe(_ value: LosslessJSONValue) -> String { + switch value { + case .object(let members): "object(\(members.count) members)" + case .array(let elements): "array(\(elements.count))" + case .string(let text): "\"\(text)\"" + case .number(let lexeme): lexeme + case .boolean(let flag): "\(flag)" + case .null: "null" + } + } +} + + +/// Pins the converter's current wire output, token for token, so the refactor can be proven identical. +/// +/// Each case converts fixed inputs through the OLD API and compares the graph's stored JSON (`ExchangeGraph.jsonData`, +/// the bytes a consumer uploads) with the checked-in golden over lossless tokens: member order is free, array order +/// and decimal lexemes are not. A failure names the first differing path. +@Suite +struct GoldenGraphTests { + @Test(.enabled(if: !GoldenStore.isGenerating), arguments: GoldenCase.all) + func matchesCheckedInGolden(_ goldenCase: GoldenCase) throws { + let output = try goldenCase.output() + let actual = try LosslessJSONValue(parsing: output.graph.jsonData) + let expected = try LosslessJSONValue(parsing: GoldenStore.data(named: goldenCase.name)) + let outline = try #require(GoldenStore.outlines()[goldenCase.name], "no outline is pinned for \(goldenCase.name)") + + #expect( + GoldenOutline(actual, warnings: output.renderedWarnings) == outline, + "\(goldenCase.name): entry, identifier, extension or warning order drifted" + ) + #expect( + GoldenOutline(expected, warnings: outline.warnings) == outline, + "\(goldenCase.name): outlines.json does not describe the checked-in golden" + ) + if let difference = TokenDiff.firstDifference(expected: expected, actual: actual) { + Issue.record("\(goldenCase.name) drifted from its golden at \(difference)") + } + } + + /// The goldens directory and `outlines.json` name exactly the cases: nothing is missing, and nothing lingers + /// after a case is renamed or removed. The first check also keeps the lookup honest, as an empty listing fails it. + @Test + func everyCheckedInGoldenBelongsToACase() throws { + let cases = Set(GoldenCase.all.map(\.name)) + let checkedIn = GoldenStore.checkedInNames + #expect(checkedIn.isSuperset(of: cases), "cases without a golden: \(cases.subtracting(checkedIn).sorted())") + let strays = checkedIn.subtracting(cases).subtracting([GoldenStore.outlinesName]).subtracting(GoldenCase.unavailableHere) + #expect(strays.isEmpty, "goldens without a case: \(strays.sorted())") + let strayOutlines = Set(try GoldenStore.outlines().keys).subtracting(cases).subtracting(GoldenCase.unavailableHere) + #expect(strayOutlines.isEmpty, "outlines without a case: \(strayOutlines.sorted())") + } + + /// Every case is named once, mints its own event, converts to the same tokens and warnings twice in one process, + /// and re-encodes with sorted members to the same tokens as its wire bytes. With `GROVE_GOLDEN_OUTPUT_DIR` set, + /// this is also the regeneration: each case's sorted-member JSON and the outlines are written there. + @Test + func everyCaseIsDeterministicAndPinnable() throws { + var outlines: [String: GoldenOutline] = [:] + var events: [String: String] = [:] + for goldenCase in GoldenCase.all { + let output = try goldenCase.output() + let graph = output.graph + let wire = try LosslessJSONValue(parsing: graph.jsonData) + let again = try goldenCase.output() + #expect(try LosslessJSONValue(parsing: again.graph.jsonData) == wire, "\(goldenCase.name) is not deterministic") + #expect(again.warnings == output.warnings, "\(goldenCase.name) does not warn deterministically") + let sorted = try GoldenStore.encoder.encode(graph.bundle) + #expect(try LosslessJSONValue(parsing: sorted) == wire, "\(goldenCase.name): a sorted re-encode changes the tokens") + + let outline = GoldenOutline(wire, warnings: output.renderedWarnings) + #expect(outlines.updateValue(outline, forKey: goldenCase.name) == nil, "\(goldenCase.name) is named twice") + let event = graph.eventIdentifier.identifier.value + #expect(events.updateValue(goldenCase.name, forKey: event) == nil, "\(goldenCase.name) shares its event with \(events[event] ?? "")") + + if let directory = GoldenStore.outputDirectory { + try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true) + try sorted.write(to: directory.appendingPathComponent("\(goldenCase.name).json")) + } + } + if let directory = GoldenStore.outputDirectory { + try GoldenStore.encoder.encode(outlines).write(to: directory.appendingPathComponent("\(GoldenStore.outlinesName).json")) + } + } + + /// The old converter refuses every `HKWorkout`: its segment children claim a profile the Provenance contract does + /// not admit. Pinned as the refusal it is, so the rework's workout output is a deliberate change, not a silent one. + @Test(arguments: [false, true]) + func workoutsAreRefused(withEvents: Bool) throws { + let workout = try StoredSampleFixtures.stored(try GoldenFixtures.workout(withEvents: withEvents), uuid: GoldenFixtures.uuid(0xA0)) + let context = try GoldenFixtures.context(sequence: 200) + let error = #expect(throws: HealthKitConversionError.self) { + try HealthKitConverter().convert(workout, context: context) + } + let diagnostic = try #require(error?.diagnostic) + #expect(diagnostic.code == "mobile-exchange.adapter-provenance-graph") + #expect(diagnostic.location == "Provenance.entity") + } + + /// A writer whose bundle identifier is not one is a refusal; a writer with a blank name is merely no writer + /// (`writer-blank-name-with-sync-identity` pins that graph). + @Test + func invalidWriterBundleIdentifierIsRefused() throws { + var writer = GoldenFixtures.foreignWriter + writer.bundleIdentifier = "not a bundle id" + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0xA1), writer: writer) + let context = try GoldenFixtures.context(sequence: 201) + #expect(throws: HealthKitConversionError.sourceApplicationInvalid) { + try HealthKitConverter().convert(sample, context: context) + } + } + + /// The comparison is the exchange protocol's: member order free, array order and decimal lexemes fixed. + @Test + func tokenDifferencesAreNamedByPath() throws { + func tokens(_ json: String) throws -> LosslessJSONValue { + try LosslessJSONValue(parsing: Data(json.utf8)) + } + let golden = try tokens(#"{"entry":[{"fullUrl":"a","resource":{"value":72}}],"timestamp":"t"}"#) + let reordered = try tokens(#"{"timestamp":"t","entry":[{"resource":{"value":72},"fullUrl":"a"}]}"#) + let lexeme = try tokens(#"{"entry":[{"fullUrl":"a","resource":{"value":72.0}}],"timestamp":"t"}"#) + let longer = try tokens(#"{"entry":[{"fullUrl":"a","resource":{"value":72}},{"fullUrl":"b"}],"timestamp":"t"}"#) + let renamed = try tokens(#"{"entry":[{"fullUrl":"a","resource":{"valueX":72}}],"timestamp":"t"}"#) + #expect(TokenDiff.firstDifference(expected: golden, actual: reordered) == nil) + #expect(TokenDiff.firstDifference(expected: golden, actual: lexeme) == "$.entry[0].resource.value: golden 72, actual 72.0") + #expect(TokenDiff.firstDifference(expected: golden, actual: longer) == "$.entry: golden has 1 elements, actual has 2") + #expect(TokenDiff.firstDifference(expected: golden, actual: renamed) == "$.entry[0].resource.value: missing, golden has 72") + #expect(GoldenOutline(golden, warnings: []) == GoldenOutline(reordered, warnings: [])) + #expect(GoldenOutline(golden, warnings: []) != GoldenOutline(longer, warnings: [])) + #expect(GoldenOutline(golden, warnings: ["a"]) != GoldenOutline(golden, warnings: [])) + } +} + + +extension LosslessJSONValue { + var elements: [LosslessJSONValue]? { // swiftlint:disable:this discouraged_optional_collection + guard case .array(let elements) = self else { + return nil + } + return elements + } + + var text: String? { + guard case .string(let text) = self else { + return nil + } + return text + } + + subscript(member: String) -> LosslessJSONValue? { + guard case .object(let members) = self else { + return nil + } + return members[member] + } +} + + +extension GoldenCase { + /// Goldens generated on macOS for cases this platform cannot build. + static var unavailableHere: Set { + #if os(watchOS) + ["clinical-document"] + #else + [] + #endif + } +} + + +extension GoldenFixtures { + /// The benchmark's one-hour run: with events, a pause and resume, eight laps and two segments, which the old + /// converter turns into twelve segment children before refusing the graph. + static func workout(withEvents: Bool) throws -> HKWorkout { + guard let workout = SampleFactory.workouts(count: 1, withEvents: withEvents).first as? HKWorkout else { + throw GoldenCaseError.workoutNotBuilt + } + return workout + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/blood-pressure-correlation.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/blood-pressure-correlation.json new file mode 100644 index 000000000..4f58d13cd --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/blood-pressure-correlation.json @@ -0,0 +1,482 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:HJhsGCU0HGa7Aqd5tovsAlqoRUbEanhnWhyg2YvlLYs" + } + } + ], + "fullUrl" : "urn:uuid:7c02d4b0-6930-54ba-abdc-b13fddf9d455", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "85354-9", + "display" : "Blood pressure panel with all children optional", + "system" : "http://loinc.org" + } + ] + }, + "component" : [ + { + "code" : { + "coding" : [ + { + "code" : "8480-6", + "system" : "http://loinc.org" + } + ] + }, + "valueQuantity" : { + "code" : "mm[Hg]", + "system" : "http://unitsofmeasure.org", + "unit" : "mmHg", + "value" : 120 + } + }, + { + "code" : { + "coding" : [ + { + "code" : "8462-4", + "system" : "http://loinc.org" + } + ] + }, + "valueQuantity" : { + "code" : "mm[Hg]", + "system" : "http://unitsofmeasure.org", + "unit" : "mmHg", + "value" : 80 + } + } + ], + "device" : { + "reference" : "urn:uuid:d2cd468b-2987-5199-b4c0-48c5eec53859" + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKCorrelationTypeIdentifierBloodPressure" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:vLdiWMfbEdPYj0ZhB2yGpzKc4LWgjn8AKpfulR4al70" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:HJhsGCU0HGa7Aqd5tovsAlqoRUbEanhnWhyg2YvlLYs" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-pressure", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:CQ0jODSC-bNYoRR0_AHtgC4Q_JizgYcUY_y9hjljmog" + } + } + ], + "fullUrl" : "urn:uuid:d2cd468b-2987-5199-b4c0-48c5eec53859", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:CQ0jODSC-bNYoRR0_AHtgC4Q_JizgYcUY_y9hjljmog" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7-32qRTb-NQabioMS2xoogyed9aSAajDlWKB6A3KbQk" + } + } + ], + "fullUrl" : "urn:uuid:8f81e542-3dfd-5054-b22f-d53c0823a33a", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7-32qRTb-NQabioMS2xoogyed9aSAajDlWKB6A3KbQk" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:67Lhzk6u228PXAzIdweio4NGJJD3oTKloIqbVqUReKw" + } + } + ], + "fullUrl" : "urn:uuid:d0c7ce86-5213-531a-ad32-cb529f53e124", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:67Lhzk6u228PXAzIdweio4NGJJD3oTKloIqbVqUReKw" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:8f81e542-3dfd-5054-b22f-d53c0823a33a" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:VN5nga9v_1F2D_pgAtr6jipeJ4KexkbrEMbYuwkVjoA" + } + } + ], + "fullUrl" : "urn:uuid:523d31e8-ce2e-5977-8f14-426a81e6ca23", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:d0c7ce86-5213-531a-ad32-cb529f53e124" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:vLdiWMfbEdPYj0ZhB2yGpzKc4LWgjn8AKpfulR4al70" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:7c02d4b0-6930-54ba-abdc-b13fddf9d455" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:9" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/body-mass-user-entered.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/body-mass-user-entered.json new file mode 100644 index 000000000..d9caf7a08 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/body-mass-user-entered.json @@ -0,0 +1,358 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:F6fP40xYTCErdBIkNK4EIX6TSvP-dAfEc6HiM5eL0zI" + } + } + ], + "fullUrl" : "urn:uuid:fb2b9e67-66d9-59c7-ad40-ea775fe3b868", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "29463-7", + "display" : "Body weight", + "system" : "http://loinc.org" + } + ] + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierBodyMass" + }, + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-method", + "valueCoding" : { + "code" : "manual-entry", + "display" : "Manual entry", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-recording-method" + } + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:9CgPOpef1tVsmk6EJLj4bHDFqZjlSP3_YFNbUf3ytO0" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:F6fP40xYTCErdBIkNK4EIX6TSvP-dAfEc6HiM5eL0zI" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "kg", + "system" : "http://unitsofmeasure.org", + "unit" : "kg", + "value" : 71.3 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:bfAm_8-MNzij0e97hfE7pzZS1j6jMFvxhdqjxzJ4J8A" + } + } + ], + "fullUrl" : "urn:uuid:73f08f07-d15f-56d8-9e05-2284b4257115", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:bfAm_8-MNzij0e97hfE7pzZS1j6jMFvxhdqjxzJ4J8A" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:JuZ6_LIOGPqBp4ARA79_zsVhTPr1T7_1_9I13pImZlE" + } + } + ], + "fullUrl" : "urn:uuid:60480b75-8e2f-5965-8304-cbc631ebf103", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:JuZ6_LIOGPqBp4ARA79_zsVhTPr1T7_1_9I13pImZlE" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:73f08f07-d15f-56d8-9e05-2284b4257115" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:MoqszMhYfOt45hA8FtGGZxcFD0upGtaDfsahBlNsyj4" + } + } + ], + "fullUrl" : "urn:uuid:b1cc275d-98bd-599c-8ed3-1199de610a33", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:60480b75-8e2f-5965-8304-cbc631ebf103" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:9CgPOpef1tVsmk6EJLj4bHDFqZjlSP3_YFNbUf3ytO0" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:fb2b9e67-66d9-59c7-ad40-ea775fe3b868" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:13" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/bundled-patient-subject.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/bundled-patient-subject.json new file mode 100644 index 000000000..2ad984f15 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/bundled-patient-subject.json @@ -0,0 +1,632 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:bTcTOBWHOO59CuWRcxRiszcArYdSNMtMRRDeYq0ofYI" + } + } + ], + "fullUrl" : "urn:uuid:650fea1f-8ed4-5da7-9ae4-5818aa9b9723", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "device" : { + "reference" : "urn:uuid:ca0e3e67-0999-5780-84db-8d7124905621" + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:kZgmCleuRbCorIFh8TYwlJKZ0G7xxJjPPILaB_ofGXI" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:bTcTOBWHOO59CuWRcxRiszcArYdSNMtMRRDeYq0ofYI" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "reference" : "urn:uuid:d4ed1c3e-f2d8-5934-8b30-f763563944d5", + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:patient:0:vP7WwCuUzjxnH_0-ASUYzE2c9GGgwS2NK2FnW55BbtQ" + } + } + ], + "fullUrl" : "urn:uuid:d4ed1c3e-f2d8-5934-8b30-f763563944d5", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + } + ], + "resourceType" : "Patient" + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:obS6ZZln0e8HpGaJGSLbhDju94K0R1XKF-Gzbvjo_wI" + } + } + ], + "fullUrl" : "urn:uuid:ca0e3e67-0999-5780-84db-8d7124905621", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:obS6ZZln0e8HpGaJGSLbhDju94K0R1XKF-Gzbvjo_wI" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:R68gsXOmise6Dzaom-ZmFVQ0qVflQmxfCRI7OL4G_KI" + } + } + ], + "fullUrl" : "urn:uuid:4dae8507-5cc2-5c70-97cf-e1fe97528ec6", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:R68gsXOmise6Dzaom-ZmFVQ0qVflQmxfCRI7OL4G_KI" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:V8y_3IHBJVsf5HzFrCfRBGyrYLvN-eCGxV0iqOnBt5c" + } + } + ], + "fullUrl" : "urn:uuid:179aa15e-38a6-520d-9db2-6f53180ce523", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:V8y_3IHBJVsf5HzFrCfRBGyrYLvN-eCGxV0iqOnBt5c" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:4dae8507-5cc2-5c70-97cf-e1fe97528ec6" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7zKG772wpnhNjRFdQUlSF2bgzCLS0psSYI8jDlCBDmI" + } + } + ], + "fullUrl" : "urn:uuid:27bc90ae-3192-5159-990d-4764c5569192", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7zKG772wpnhNjRFdQUlSF2bgzCLS0psSYI8jDlCBDmI" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "iPhone17,1", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "26.1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:NEec450y0sraR7xbqWgH3yVUfbenpZd3_EXE6szNmrM" + } + } + ], + "fullUrl" : "urn:uuid:dafff25f-7b2a-50f1-8062-35eaaa6d3c23", + "resource" : { + "deviceName" : [ + { + "name" : "Example Writer", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:NEec450y0sraR7xbqWgH3yVUfbenpZd3_EXE6szNmrM" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.example.writer" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:27bc90ae-3192-5159-990d-4764c5569192" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "42" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:AWWUzyjfrKm8NU0du61dXiVrFNB32nZYihcpuek8rUc" + } + } + ], + "fullUrl" : "urn:uuid:be2a33d7-8e5f-5fa9-9a3d-b5a0ee9a747c", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:179aa15e-38a6-520d-9db2-6f53180ce523" + } + } + ], + "entity" : [ + { + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "author", + "display" : "Author", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:dafff25f-7b2a-50f1-8062-35eaaa6d3c23" + } + } + ], + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:kZgmCleuRbCorIFh8TYwlJKZ0G7xxJjPPILaB_ofGXI" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:650fea1f-8ed4-5da7-9ae4-5818aa9b9723" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:44" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/clinical-document.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/clinical-document.json new file mode 100644 index 000000000..2872e0642 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/clinical-document.json @@ -0,0 +1,356 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:keBDoyNksAXgYsWVUD4BFLHyipaDAc9Ycnhbv0SQXTY" + } + } + ], + "fullUrl" : "urn:uuid:522e0b85-6287-5760-9cdb-8cbe87ee4011", + "resource" : { + "author" : [ + { + "reference" : "urn:uuid:5cc49e86-4d50-5d36-8c05-1f2401721cd0" + } + ], + "content" : [ + { + "attachment" : { + "contentType" : "application/hl7-cda+xml", + "data" : "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPENsaW5pY2FsRG9jdW1lbnQgeG1sbnM9InVybjpobDctb3JnOnYzIj4KICA8dHlwZUlkIHJvb3Q9IjIuMTYuODQwLjEuMTEzODgzLjEuMyIgZXh0ZW5zaW9uPSJQT0NEX0hEMDAwMDQwIi8+CiAgPGlkIHJvb3Q9IjIuMTYuODQwLjEuMTEzODgzLjE5LjUiIGV4dGVuc2lvbj0iZ3JvdmUtZ29sZGVuLTEiLz4KICA8Y29kZSBjb2RlPSIzNDEzMy05IiBjb2RlU3lzdGVtPSIyLjE2Ljg0MC4xLjExMzg4My42LjEiIGRpc3BsYXlOYW1lPSJTdW1tYXJpemF0aW9uIG9mIEVwaXNvZGUgTm90ZSIvPgogIDx0aXRsZT5Hcm92ZSBHb2xkZW4gU3VtbWFyeTwvdGl0bGU+CiAgPGVmZmVjdGl2ZVRpbWUgdmFsdWU9IjIwMjYwODE3MTUzMDAwIi8+CiAgPGNvbmZpZGVudGlhbGl0eUNvZGUgY29kZT0iTiIgY29kZVN5c3RlbT0iMi4xNi44NDAuMS4xMTM4ODMuNS4yNSIvPgogIDxsYW5ndWFnZUNvZGUgY29kZT0iZW4tVVMiLz4KICA8cmVjb3JkVGFyZ2V0PjxwYXRpZW50Um9sZT48aWQgcm9vdD0iMi4xNi44NDAuMS4xMTM4ODMuMTkuNSIgZXh0ZW5zaW9uPSJwLTEiLz48cGF0aWVudD48bmFtZT48Z2l2ZW4+RXhhbXBsZTwvZ2l2ZW4+PGZhbWlseT5QYXJ0aWNpcGFudDwvZmFtaWx5PjwvbmFtZT48L3BhdGllbnQ+PC9wYXRpZW50Um9sZT48L3JlY29yZFRhcmdldD4KICA8YXV0aG9yPjx0aW1lIHZhbHVlPSIyMDI2MDgxNzE1MzAwMCIvPjxhc3NpZ25lZEF1dGhvcj48aWQgcm9vdD0iMi4xNi44NDAuMS4xMTM4ODMuMTkuNSIgZXh0ZW5zaW9uPSJhLTEiLz48YXNzaWduZWRQZXJzb24+PG5hbWU+PGdpdmVuPkFkYTwvZ2l2ZW4+PGZhbWlseT5DbGluaWNpYW48L2ZhbWlseT48L25hbWU+PC9hc3NpZ25lZFBlcnNvbj48L2Fzc2lnbmVkQXV0aG9yPjwvYXV0aG9yPgogIDxjdXN0b2RpYW4+PGFzc2lnbmVkQ3VzdG9kaWFuPjxyZXByZXNlbnRlZEN1c3RvZGlhbk9yZ2FuaXphdGlvbj48aWQgcm9vdD0iMi4xNi44NDAuMS4xMTM4ODMuMTkuNSIgZXh0ZW5zaW9uPSJjLTEiLz48bmFtZT5FeGFtcGxlIEhvc3BpdGFsPC9uYW1lPjwvcmVwcmVzZW50ZWRDdXN0b2RpYW5Pcmdhbml6YXRpb24+PC9hc3NpZ25lZEN1c3RvZGlhbj48L2N1c3RvZGlhbj4KICA8Y29tcG9uZW50PjxzdHJ1Y3R1cmVkQm9keT48Y29tcG9uZW50PjxzZWN0aW9uPjx0aXRsZT5Ob3RlczwvdGl0bGU+PHRleHQ+RXhhbXBsZS48L3RleHQ+PC9zZWN0aW9uPjwvY29tcG9uZW50Pjwvc3RydWN0dXJlZEJvZHk+PC9jb21wb25lbnQ+CjwvQ2xpbmljYWxEb2N1bWVudD4=", + "hash" : "heouxbdCsp2l+KJ9RX8I/BSh+Vg=", + "size" : 1289, + "title" : "Grove Golden Summary" + }, + "format" : { + "code" : "clinical-document", + "system" : "https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format" + } + } + ], + "date" : "2026-08-17T23:30:00Z", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKDocumentTypeIdentifierCDA" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:1KLEBhU35GE7bcLZ8_vWmici5Op3CrzR_No7MGJvD4o" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:keBDoyNksAXgYsWVUD4BFLHyipaDAc9Ycnhbv0SQXTY" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1", + "type" : { + "coding" : [ + { + "code" : "source-artifact", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:GqFmAyiQxxDL7NfpD2FTjh-dDA8oHplVEJad0faE69Y" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-recording-document", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-recording-document" + ] + }, + "resourceType" : "DocumentReference", + "status" : "current", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "type" : { + "coding" : [ + { + "code" : "clinical-document", + "system" : "https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format" + } + ] + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:CQjW7k2FMuRv7NCI2j0QYDu_wzuNn3VwjikNsSHBUc8" + } + } + ], + "fullUrl" : "urn:uuid:450fe019-fd6b-5b19-b07c-37ca7e7ffde8", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:CQjW7k2FMuRv7NCI2j0QYDu_wzuNn3VwjikNsSHBUc8" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Jb69oEAStFO5k0ZHlgVZ7QgOQfL-fKyMvP0WcEp2jek" + } + } + ], + "fullUrl" : "urn:uuid:5cc49e86-4d50-5d36-8c05-1f2401721cd0", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Jb69oEAStFO5k0ZHlgVZ7QgOQfL-fKyMvP0WcEp2jek" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:450fe019-fd6b-5b19-b07c-37ca7e7ffde8" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:nq24frst8p-ECxUMYXUhn0mlwMfTxQILjZMCeCg5-kI" + } + } + ], + "fullUrl" : "urn:uuid:17062a17-1106-5adb-9c5e-f2d9e93ce341", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:5cc49e86-4d50-5d36-8c05-1f2401721cd0" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:1KLEBhU35GE7bcLZ8_vWmici5Op3CrzR_No7MGJvD4o" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:522e0b85-6287-5760-9cdb-8cbe87ee4011" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:64" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram-symptom-companion.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram-symptom-companion.json new file mode 100644 index 000000000..ed704f083 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram-symptom-companion.json @@ -0,0 +1,613 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:JMuXnGeBq7p_tQuIWauSJ__Y2BZk3e8klW8tV6TU-t4" + } + } + ], + "fullUrl" : "urn:uuid:4f80da53-e7aa-5bb5-b3b6-f7c857d6a562", + "resource" : { + "code" : { + "coding" : [ + { + "code" : "symptom-chest-tightness-or-pain", + "display" : "Chest tightness or pain", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement" + } + ] + }, + "device" : { + "reference" : "urn:uuid:66083dcb-56e4-5d41-bf87-ab0232e14a45" + }, + "effectivePeriod" : { + "_end" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "_start" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "end" : "2026-08-17T15:30:30-07:00", + "start" : "2026-08-17T15:30:00-07:00" + }, + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKCategoryTypeIdentifierChestTightnessOrPain" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:HZJlYgBiY4WzfqtgcMLKxZqzvSOU_R6MA0SzsEMQaqc" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:JMuXnGeBq7p_tQuIWauSJ__Y2BZk3e8klW8tV6TU-t4" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-chest-tightness-or-pain" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueCodeableConcept" : { + "coding" : [ + { + "code" : "mild", + "display" : "Mild", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity" + }, + { + "code" : "mild", + "display" : "Mild", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity" + } + ] + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:bdrO0Z5G0evQXWD7Z9o75aMzBVv06xTBr-7X5oCWkkI" + } + } + ], + "fullUrl" : "urn:uuid:66083dcb-56e4-5d41-bf87-ab0232e14a45", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:bdrO0Z5G0evQXWD7Z9o75aMzBVv06xTBr-7X5oCWkkI" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:UEL4cLZZ2F65r2sT74r9y5dQLTe88TTy5V_Q8Od7T5w" + } + } + ], + "fullUrl" : "urn:uuid:957b2550-1d36-57ef-a729-adb23cbbdf6d", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:UEL4cLZZ2F65r2sT74r9y5dQLTe88TTy5V_Q8Od7T5w" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:8IIPpVa6RgGzsLLFmOJsCgVkalyzllLnX09IZzPiXtM" + } + } + ], + "fullUrl" : "urn:uuid:87b995e3-4383-5c86-958a-6cac67c2b805", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:8IIPpVa6RgGzsLLFmOJsCgVkalyzllLnX09IZzPiXtM" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:957b2550-1d36-57ef-a729-adb23cbbdf6d" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:ev4pSJxtJxgCn6I6NDCdnbGMIjNZ8UeRnKZ37mpcoiI" + } + } + ], + "fullUrl" : "urn:uuid:342152e5-0fa1-578f-ae92-0d3bc245ea35", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:ev4pSJxtJxgCn6I6NDCdnbGMIjNZ8UeRnKZ37mpcoiI" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "iPhone17,1", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "26.1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:SsFGcQUFXzymFU5DlqvKSv5JIcmRgG5ElFKAzjodj_8" + } + } + ], + "fullUrl" : "urn:uuid:7cdf03d0-e248-5b92-901d-299e17845605", + "resource" : { + "deviceName" : [ + { + "name" : "Example Writer", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:SsFGcQUFXzymFU5DlqvKSv5JIcmRgG5ElFKAzjodj_8" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.example.writer" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:342152e5-0fa1-578f-ae92-0d3bc245ea35" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "42" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:s9oxVYyRhGqeQJ4thDYbKr0lr-gD8fsp65ar0Jq-ec8" + } + } + ], + "fullUrl" : "urn:uuid:43f1180e-d7c0-5797-9e48-0c4313172870", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:87b995e3-4383-5c86-958a-6cac67c2b805" + } + } + ], + "entity" : [ + { + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "author", + "display" : "Author", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:7cdf03d0-e248-5b92-901d-299e17845605" + } + } + ], + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:HZJlYgBiY4WzfqtgcMLKxZqzvSOU_R6MA0SzsEMQaqc" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:4f80da53-e7aa-5bb5-b3b6-f7c857d6a562" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:161" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram-with-symptom.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram-with-symptom.json new file mode 100644 index 000000000..fae0b2d9a --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram-with-symptom.json @@ -0,0 +1,764 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:aUWZCMJyOEYVCVaXUSSdpkIn1drfk6ajkMCLpT6mtBs" + } + } + ], + "fullUrl" : "urn:uuid:0786bc40-f9fe-59ec-b7a2-9d26bb724885", + "resource" : { + "code" : { + "coding" : [ + { + "code" : "11524-6", + "display" : "EKG study", + "system" : "http://loinc.org" + } + ] + }, + "component" : [ + { + "code" : { + "coding" : [ + { + "code" : "131329", + "display" : "MDC_ECG_ELEC_POTL_I", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "valueSampledData" : { + "data" : "0.125 0.25 -0.125 0", + "dimensions" : 1, + "origin" : { + "code" : "mV", + "system" : "http://unitsofmeasure.org", + "unit" : "mV", + "value" : 0 + }, + "period" : 2 + } + } + ], + "device" : { + "reference" : "urn:uuid:09445bfa-2f2d-5729-87e3-276e1710ac51" + }, + "effectivePeriod" : { + "end" : "2026-08-17T15:30:00.256-07:00", + "start" : "2026-08-17T15:30:00.25-07:00" + }, + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKDataTypeIdentifierElectrocardiogram" + }, + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status", + "valueCode" : "present" + }, + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period", + "valuePeriod" : { + "end" : "2026-08-17T15:30:30-07:00", + "start" : "2026-08-17T15:30:00-07:00" + } + } + ], + "hasMember" : [ + { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:JMuXnGeBq7p_tQuIWauSJ__Y2BZk3e8klW8tV6TU-t4" + }, + "type" : "Observation" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:-sxIw2zn3pl-JMISV5kprDK_i02tIT0Ct69amwTw6qg" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:aUWZCMJyOEYVCVaXUSSdpkIn1drfk6ajkMCLpT6mtBs" + } + ], + "interpretation" : [ + { + "coding" : [ + { + "code" : "sinusRhythm", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification" + } + ] + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation" + ] + }, + "method" : { + "coding" : [ + { + "code" : "version2", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version" + } + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:U8O093yT3aixzE4WxrTS8T-opQPH8CkYgWelojPulPg" + } + } + ], + "fullUrl" : "urn:uuid:e6dcf13b-2eb2-5ba1-912d-cf8e9b8bf45b", + "resource" : { + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "derivedFrom" : [ + { + "reference" : "urn:uuid:0786bc40-f9fe-59ec-b7a2-9d26bb724885" + } + ], + "device" : { + "reference" : "urn:uuid:09445bfa-2f2d-5729-87e3-276e1710ac51" + }, + "effectivePeriod" : { + "end" : "2026-08-17T15:30:00.256-07:00", + "start" : "2026-08-17T15:30:00.25-07:00" + }, + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKDataTypeIdentifierElectrocardiogram" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:-sxIw2zn3pl-JMISV5kprDK_i02tIT0Ct69amwTw6qg" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:U8O093yT3aixzE4WxrTS8T-opQPH8CkYgWelojPulPg" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:TZMowVmB-5la9zz95eOceigG1lda9_5sQC9wrGPHLEU" + } + } + ], + "fullUrl" : "urn:uuid:09445bfa-2f2d-5729-87e3-276e1710ac51", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:TZMowVmB-5la9zz95eOceigG1lda9_5sQC9wrGPHLEU" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:N-ePkunWLS3fcvs9rDd5uh5ltmoRt7EmotuxWRTo7vA" + } + } + ], + "fullUrl" : "urn:uuid:17155fd0-ad6a-52c4-a946-4468106caffa", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:N-ePkunWLS3fcvs9rDd5uh5ltmoRt7EmotuxWRTo7vA" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:BYBvIKW5wu4S6evy4SPZQOFB37YD2y8s3Hcg6E6_KE0" + } + } + ], + "fullUrl" : "urn:uuid:219bc452-900a-5a4d-8777-ecbfc1f6a85f", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:BYBvIKW5wu4S6evy4SPZQOFB37YD2y8s3Hcg6E6_KE0" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:17155fd0-ad6a-52c4-a946-4468106caffa" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:s8buBEyG4yRzKd2hA02jUKfwT2IN5N5psYD2moM7mb4" + } + } + ], + "fullUrl" : "urn:uuid:08844702-36cb-57ff-b249-2b1b843fb79f", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:s8buBEyG4yRzKd2hA02jUKfwT2IN5N5psYD2moM7mb4" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "iPhone17,1", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "26.1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7oVlArgLSpX9m-sICbkampE5_6rdy4EpAz-xyYWON1o" + } + } + ], + "fullUrl" : "urn:uuid:965a804c-2f33-5fe0-ae1e-a4a328007269", + "resource" : { + "deviceName" : [ + { + "name" : "Example Writer", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7oVlArgLSpX9m-sICbkampE5_6rdy4EpAz-xyYWON1o" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.example.writer" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:08844702-36cb-57ff-b249-2b1b843fb79f" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "42" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:SGgJa9JwiGnUuKBk6WN3ra9YDzJfcKNHbx_RGg32zi0" + } + } + ], + "fullUrl" : "urn:uuid:8a8b3433-b274-5da2-8db1-7c0d4004f7ec", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:219bc452-900a-5a4d-8777-ecbfc1f6a85f" + } + } + ], + "entity" : [ + { + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "author", + "display" : "Author", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:965a804c-2f33-5fe0-ae1e-a4a328007269" + } + } + ], + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:-sxIw2zn3pl-JMISV5kprDK_i02tIT0Ct69amwTw6qg" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:0786bc40-f9fe-59ec-b7a2-9d26bb724885" + }, + { + "reference" : "urn:uuid:e6dcf13b-2eb2-5ba1-912d-cf8e9b8bf45b" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:61" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram.json new file mode 100644 index 000000000..a73617a4b --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram.json @@ -0,0 +1,747 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:oUFZxFHM9ZPeflL9v9vdkmv-K_UDjOb_bH0DeVFFY-k" + } + } + ], + "fullUrl" : "urn:uuid:71eb02d9-992e-50b1-b859-4988b669ea26", + "resource" : { + "code" : { + "coding" : [ + { + "code" : "11524-6", + "display" : "EKG study", + "system" : "http://loinc.org" + } + ] + }, + "component" : [ + { + "code" : { + "coding" : [ + { + "code" : "131329", + "display" : "MDC_ECG_ELEC_POTL_I", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "valueSampledData" : { + "data" : "0.125 0.25 -0.125 0", + "dimensions" : 1, + "origin" : { + "code" : "mV", + "system" : "http://unitsofmeasure.org", + "unit" : "mV", + "value" : 0 + }, + "period" : 2 + } + } + ], + "device" : { + "reference" : "urn:uuid:74b08d9e-cbc8-50d1-9680-4c3f9286f1f3" + }, + "effectivePeriod" : { + "end" : "2026-08-17T15:30:00.256-07:00", + "start" : "2026-08-17T15:30:00.25-07:00" + }, + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKDataTypeIdentifierElectrocardiogram" + }, + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status", + "valueCode" : "none" + }, + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period", + "valuePeriod" : { + "end" : "2026-08-17T15:30:30-07:00", + "start" : "2026-08-17T15:30:00-07:00" + } + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:hIzISl6FuqMWdHZcjP-B2_ksukup6BnRgGqsPPiVe6g" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:oUFZxFHM9ZPeflL9v9vdkmv-K_UDjOb_bH0DeVFFY-k" + } + ], + "interpretation" : [ + { + "coding" : [ + { + "code" : "sinusRhythm", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification" + } + ] + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation" + ] + }, + "method" : { + "coding" : [ + { + "code" : "version2", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version" + } + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:ayjux3kQuPNZ8LpeJo_AS0R2Z_mfSJjlyS2kQBrtfPI" + } + } + ], + "fullUrl" : "urn:uuid:ef688b88-8189-5ca7-aaca-951235dc4daf", + "resource" : { + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "derivedFrom" : [ + { + "reference" : "urn:uuid:71eb02d9-992e-50b1-b859-4988b669ea26" + } + ], + "device" : { + "reference" : "urn:uuid:74b08d9e-cbc8-50d1-9680-4c3f9286f1f3" + }, + "effectivePeriod" : { + "end" : "2026-08-17T15:30:00.256-07:00", + "start" : "2026-08-17T15:30:00.25-07:00" + }, + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKDataTypeIdentifierElectrocardiogram" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:hIzISl6FuqMWdHZcjP-B2_ksukup6BnRgGqsPPiVe6g" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:ayjux3kQuPNZ8LpeJo_AS0R2Z_mfSJjlyS2kQBrtfPI" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:9EW_T3EzD9L34WmvN-K2Dy28CU_HykiShypagj0B3rs" + } + } + ], + "fullUrl" : "urn:uuid:74b08d9e-cbc8-50d1-9680-4c3f9286f1f3", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:9EW_T3EzD9L34WmvN-K2Dy28CU_HykiShypagj0B3rs" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:WWpRG50Fmgy4qqc6KCNlXGGxAgh6M-XyMRWOZ4rs6Gc" + } + } + ], + "fullUrl" : "urn:uuid:1319dc48-a2ee-572f-b3b4-3b5fe7104a85", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:WWpRG50Fmgy4qqc6KCNlXGGxAgh6M-XyMRWOZ4rs6Gc" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:VDIX5JqXoM-Le5Rs8unycEU6vlLw3FS4A2ENFt-2y80" + } + } + ], + "fullUrl" : "urn:uuid:fd6347b4-6143-5ace-b626-ce0e1e0e57fe", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:VDIX5JqXoM-Le5Rs8unycEU6vlLw3FS4A2ENFt-2y80" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:1319dc48-a2ee-572f-b3b4-3b5fe7104a85" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:CqlhnFqMlGAci4vaQkCBgBeUJF9aA3J1bjjEXCs6pNE" + } + } + ], + "fullUrl" : "urn:uuid:659ba41a-b773-5177-9923-8a596c45de30", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:CqlhnFqMlGAci4vaQkCBgBeUJF9aA3J1bjjEXCs6pNE" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "iPhone17,1", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "26.1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:ZhPvEZjeAyTc7gzk7uluiB_0SIAc29eOtaofueV0kCs" + } + } + ], + "fullUrl" : "urn:uuid:ac9e967e-1606-58e5-8a33-72e6f7e602af", + "resource" : { + "deviceName" : [ + { + "name" : "Example Writer", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:ZhPvEZjeAyTc7gzk7uluiB_0SIAc29eOtaofueV0kCs" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.example.writer" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:659ba41a-b773-5177-9923-8a596c45de30" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "42" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:YEmedF2cnR_xVZUJ3UA4ExaM29vqxtfJPqWyp7WywHI" + } + } + ], + "fullUrl" : "urn:uuid:68e0a782-d8a1-5e27-aaa9-b0c272c89904", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:fd6347b4-6143-5ace-b626-ce0e1e0e57fe" + } + } + ], + "entity" : [ + { + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "author", + "display" : "Author", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:ac9e967e-1606-58e5-8a33-72e6f7e602af" + } + } + ], + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:hIzISl6FuqMWdHZcjP-B2_ksukup6BnRgGqsPPiVe6g" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:71eb02d9-992e-50b1-b859-4988b669ea26" + }, + { + "reference" : "urn:uuid:ef688b88-8189-5ca7-aaca-951235dc4daf" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:60" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/gateway-application-role.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/gateway-application-role.json new file mode 100644 index 000000000..88f27e89d --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/gateway-application-role.json @@ -0,0 +1,687 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:qDMUHRvr7xVoEjlMqF4oQpjiXZPTRmaawKpTmh0hxZM" + } + } + ], + "fullUrl" : "urn:uuid:a88e060e-ec7c-5ec0-8b0e-6b7356e7fa9e", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "device" : { + "reference" : "urn:uuid:04f063a3-bc62-545f-a0b8-11df9af133d2" + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + }, + { + "url" : "http://hl7.org/fhir/StructureDefinition/observation-gatewayDevice", + "valueReference" : { + "reference" : "urn:uuid:3ec42d04-7eae-5c23-82c4-e94e197f0689" + } + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:JBRlTi02jeW9eRSv9XELCh4dhoYzM9dKYgs7qjnt0_g" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:qDMUHRvr7xVoEjlMqF4oQpjiXZPTRmaawKpTmh0hxZM" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:WDBinr5w7PcvcaRoBNjWHPRhjGyOqM4yC41LwfI3Z24" + } + } + ], + "fullUrl" : "urn:uuid:04f063a3-bc62-545f-a0b8-11df9af133d2", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:WDBinr5w7PcvcaRoBNjWHPRhjGyOqM4yC41LwfI3Z24" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:n2EmlS9mA64HvuKSRZvPQ_DLqUHhITDmpPeSxuo31Qc" + } + } + ], + "fullUrl" : "urn:uuid:269b221d-c646-53f1-aa9d-915c11263c4e", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:n2EmlS9mA64HvuKSRZvPQ_DLqUHhITDmpPeSxuo31Qc" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:qQviYoSoPxQMtwJNPGZ5o7kjf2fl3QdHBcnPIshRxho" + } + } + ], + "fullUrl" : "urn:uuid:86793a3d-e936-5a9e-8221-13afab7db244", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:qQviYoSoPxQMtwJNPGZ5o7kjf2fl3QdHBcnPIshRxho" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:269b221d-c646-53f1-aa9d-915c11263c4e" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:o2qpZsBSsRdBi4QW3djT5K4Nx6B0i87AIAloYcV7kBQ" + } + } + ], + "fullUrl" : "urn:uuid:3ec42d04-7eae-5c23-82c4-e94e197f0689", + "resource" : { + "deviceName" : [ + { + "name" : "Cuff Companion", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:o2qpZsBSsRdBi4QW3djT5K4Nx6B0i87AIAloYcV7kBQ" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "com.example.cuff" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "3.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:08kGbsvdtUqZumirucowZS9ePH45abfoM5O4nNX7rkk" + } + } + ], + "fullUrl" : "urn:uuid:48aeeb20-6643-5b41-b3a3-44093a548f15", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:08kGbsvdtUqZumirucowZS9ePH45abfoM5O4nNX7rkk" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "iPhone17,1", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "26.1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:J9lvvDAXkS_dbdj52mxPi9OlB8TwcLXwadZ2GWu6m4Q" + } + } + ], + "fullUrl" : "urn:uuid:480efa67-eb12-5f15-92ba-fbc30cf24d40", + "resource" : { + "deviceName" : [ + { + "name" : "Example Writer", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:J9lvvDAXkS_dbdj52mxPi9OlB8TwcLXwadZ2GWu6m4Q" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.example.writer" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:48aeeb20-6643-5b41-b3a3-44093a548f15" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "42" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:BL4rFVs8Smef-nvw_jofAcNiwhkfzOg3YWlH9rithaA" + } + } + ], + "fullUrl" : "urn:uuid:134073a9-d5de-5dd9-abaf-6b7bb226f0a5", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:86793a3d-e936-5a9e-8221-13afab7db244" + } + } + ], + "entity" : [ + { + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "author", + "display" : "Author", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:480efa67-eb12-5f15-92ba-fbc30cf24d40" + } + } + ], + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:JBRlTi02jeW9eRSv9XELCh4dhoYzM9dKYgs7qjnt0_g" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:a88e060e-ec7c-5ec0-8b0e-6b7356e7fa9e" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:43" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/gateway-role.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/gateway-role.json new file mode 100644 index 000000000..3367ec691 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/gateway-role.json @@ -0,0 +1,612 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:y0zwisf7fEMxJ5H1xFk6erxnBpS828ph8teZOqYhPZA" + } + } + ], + "fullUrl" : "urn:uuid:dbafa993-ba4f-51e0-ad7d-d796ddd5ef67", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "device" : { + "reference" : "urn:uuid:ec2cb5c9-19da-5d18-bb0e-85d60b7ddb81" + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + }, + { + "url" : "http://hl7.org/fhir/StructureDefinition/observation-gatewayDevice", + "valueReference" : { + "reference" : "urn:uuid:4a209379-2c63-56e3-9767-a3c44f6b3b90" + } + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:McX70VJJ-8FCgv1530lWhJkyrzUfPpP0aF8zkUnT1j8" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:y0zwisf7fEMxJ5H1xFk6erxnBpS828ph8teZOqYhPZA" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:9ySy4ypKV6MKykXXkoertO-a3k5upQix_qDPvkaZea0" + } + } + ], + "fullUrl" : "urn:uuid:ec2cb5c9-19da-5d18-bb0e-85d60b7ddb81", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:9ySy4ypKV6MKykXXkoertO-a3k5upQix_qDPvkaZea0" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:15QiZ156dS5FCTIE4qwxG8XTq4xdjEkbTo4YplOsQWo" + } + } + ], + "fullUrl" : "urn:uuid:e35a840b-f0fc-5a54-bf90-8fee85372598", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:15QiZ156dS5FCTIE4qwxG8XTq4xdjEkbTo4YplOsQWo" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:pU1MJcL1Jj23OM_Lj2WfKnbPCczTrVqlBeup_rEzjas" + } + } + ], + "fullUrl" : "urn:uuid:4a209379-2c63-56e3-9767-a3c44f6b3b90", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:pU1MJcL1Jj23OM_Lj2WfKnbPCczTrVqlBeup_rEzjas" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:e35a840b-f0fc-5a54-bf90-8fee85372598" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:gL3lSNl7EYteXp70F6laHYwj023D9L4lpXWNgHKH-ds" + } + } + ], + "fullUrl" : "urn:uuid:1f896505-6996-55e4-8231-8412a4c864a8", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:gL3lSNl7EYteXp70F6laHYwj023D9L4lpXWNgHKH-ds" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "iPhone17,1", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "26.1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:qYBO4DwuNe0zTKt3vV2rd6GhfJZ_a6meCVdUGWQ8Aqo" + } + } + ], + "fullUrl" : "urn:uuid:1fb8e303-b58a-5107-ac2d-9ddced20bb00", + "resource" : { + "deviceName" : [ + { + "name" : "Example Writer", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:qYBO4DwuNe0zTKt3vV2rd6GhfJZ_a6meCVdUGWQ8Aqo" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.example.writer" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:1f896505-6996-55e4-8231-8412a4c864a8" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "42" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:9oxhfp6uAtIGTu_OFKMbJeeHY-mSb7njoEJ1tjicKHY" + } + } + ], + "fullUrl" : "urn:uuid:ded34666-95a9-5629-9a8a-a646a65d7949", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:4a209379-2c63-56e3-9767-a3c44f6b3b90" + } + } + ], + "entity" : [ + { + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "author", + "display" : "Author", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:1fb8e303-b58a-5107-ac2d-9ddced20bb00" + } + } + ], + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:McX70VJJ-8FCgv1530lWhJkyrzUfPpP0aF8zkUnT1j8" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:dbafa993-ba4f-51e0-ad7d-d796ddd5ef67" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:42" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-device-without-unit-token.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-device-without-unit-token.json new file mode 100644 index 000000000..70240f19d --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-device-without-unit-token.json @@ -0,0 +1,350 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:mqKBBlGQyKkNm_nQgCH3Gpyvvaea9nCO_EBIECecs40" + } + } + ], + "fullUrl" : "urn:uuid:7a259769-1a74-5890-9a8e-23bfd25b9ec2", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:bPp6yNIw-P0yHmagH5lycYA4UrqiKUpUuNEpILTibp4" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:mqKBBlGQyKkNm_nQgCH3Gpyvvaea9nCO_EBIECecs40" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:IODV7uCVRUy8uwuwRj6vAt8ztpJqRxcifZkh1u8JvlQ" + } + } + ], + "fullUrl" : "urn:uuid:ee821cbc-1292-5eb4-928b-40d31ca63779", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:IODV7uCVRUy8uwuwRj6vAt8ztpJqRxcifZkh1u8JvlQ" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Pa_emYvici83-idni_3JyQswXeUjZXEFuMOMTy4KPRg" + } + } + ], + "fullUrl" : "urn:uuid:54dc5efd-613f-5b6b-b465-8d4f0ef2852d", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Pa_emYvici83-idni_3JyQswXeUjZXEFuMOMTy4KPRg" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:ee821cbc-1292-5eb4-928b-40d31ca63779" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:ItTermNq35k_x4inKcAca9rc9KFd1QiFiI18Ignz5AU" + } + } + ], + "fullUrl" : "urn:uuid:c909f4f7-0a9b-5ceb-b215-26c878688fde", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:54dc5efd-613f-5b6b-b465-8d4f0ef2852d" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:bPp6yNIw-P0yHmagH5lycYA4UrqiKUpUuNEpILTibp4" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:7a259769-1a74-5890-9a8e-23bfd25b9ec2" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:4" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-interval.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-interval.json new file mode 100644 index 000000000..b06fe55ed --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-interval.json @@ -0,0 +1,350 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:alpiL3HSFzX615rQp5kgWJ1b3AnK4IeBNVo7QLA_yNU" + } + } + ], + "fullUrl" : "urn:uuid:1e5229cf-7fd0-5b3e-b863-30715d61c524", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:4rxRgRPFMWMMdZjfm_6SU_15FbhtTaNWNdObFGoYFRg" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:alpiL3HSFzX615rQp5kgWJ1b3AnK4IeBNVo7QLA_yNU" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:t4bJSfVWvCGBHpnbCG2wbiVs5f1fJVa01BCH6IufXoQ" + } + } + ], + "fullUrl" : "urn:uuid:c66db3b2-ae1f-5cc1-88ba-1c864c2367eb", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:t4bJSfVWvCGBHpnbCG2wbiVs5f1fJVa01BCH6IufXoQ" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:CsxkUTODH696XsMQgxN64nOFEeUxwN0xvHAEZfw0vKs" + } + } + ], + "fullUrl" : "urn:uuid:0cf2a54e-f04e-5f26-a122-c294493a0923", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:CsxkUTODH696XsMQgxN64nOFEeUxwN0xvHAEZfw0vKs" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:c66db3b2-ae1f-5cc1-88ba-1c864c2367eb" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:Jmmj4pXQyb81gz6c_h5ZCdW7eG8QtvfiW8-LV9mYvDk" + } + } + ], + "fullUrl" : "urn:uuid:bc374b4f-e99a-5487-9194-f15e081f6cb4", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:0cf2a54e-f04e-5f26-a122-c294493a0923" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:4rxRgRPFMWMMdZjfm_6SU_15FbhtTaNWNdObFGoYFRg" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:1e5229cf-7fd0-5b3e-b863-30715d61c524" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:6" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-minimal.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-minimal.json new file mode 100644 index 000000000..2e738358e --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-minimal.json @@ -0,0 +1,342 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:tfWplyF8loEu85zzoEd3najBmp1FgU9xJGD9Pka_-3E" + } + } + ], + "fullUrl" : "urn:uuid:43a60a20-f034-5ad7-9f00-f65aac29503c", + "resource" : { + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "effectiveDateTime" : "2026-08-17T22:30:00Z", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:QxmbFs_KgP8IGB0zSPXhCdpTD6t0M14cf7yY-d_SnD8" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:tfWplyF8loEu85zzoEd3najBmp1FgU9xJGD9Pka_-3E" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7CHu7jAo4aD4P_YJAGl7D2HoTu7jnFRqNgfxWygnOQ8" + } + } + ], + "fullUrl" : "urn:uuid:a11ff194-13a8-5786-8fca-9848678e78d6", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7CHu7jAo4aD4P_YJAGl7D2HoTu7jnFRqNgfxWygnOQ8" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:2yoi5jK0yGmK7znYdA-VNwyn13nwyTvg63St3ZoMMMk" + } + } + ], + "fullUrl" : "urn:uuid:66d6c515-f557-52a5-bcaf-fe94b965f94b", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:2yoi5jK0yGmK7znYdA-VNwyn13nwyTvg63St3ZoMMMk" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:a11ff194-13a8-5786-8fca-9848678e78d6" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:zbdmPsD1v1DgGr4zVMlSuftwpZVXhZx-I40dyJbW3yA" + } + } + ], + "fullUrl" : "urn:uuid:fd512c31-6e2a-5d5c-aab5-59631ebfb8d0", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:66d6c515-f557-52a5-bcaf-fe94b965f94b" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:QxmbFs_KgP8IGB0zSPXhCdpTD6t0M14cf7yY-d_SnD8" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:43a60a20-f034-5ad7-9f00-f65aac29503c" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:1" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-motion-context.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-motion-context.json new file mode 100644 index 000000000..cbd9d5820 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-motion-context.json @@ -0,0 +1,476 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:3pyNyAsRSdh8eIJW6Mpn_15dioT3PgGTjhyKX-ZvTLY" + } + } + ], + "fullUrl" : "urn:uuid:5b585439-a9f5-5e29-b7ff-a546e0635440", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "component" : [ + { + "code" : { + "coding" : [ + { + "code" : "HKMetadataKeyHeartRateMotionContext", + "display" : "Heart Rate Motion Context", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-metadata-key" + } + ] + }, + "valueCodeableConcept" : { + "coding" : [ + { + "code" : "active", + "display" : "Active", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-heart-rate-motion-context" + } + ] + } + } + ], + "device" : { + "reference" : "urn:uuid:3228e4b0-e429-538c-af60-19d75dccc91b" + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:UhqDpMunyA3OXTgy0e8OBXov4_RG9AXVMh4HAlwurJ8" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:3pyNyAsRSdh8eIJW6Mpn_15dioT3PgGTjhyKX-ZvTLY" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:lslI_JP2D6DtsNS62crvUo9_6oQ9u3ZmarhkLaxZv_E" + } + } + ], + "fullUrl" : "urn:uuid:3228e4b0-e429-538c-af60-19d75dccc91b", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:lslI_JP2D6DtsNS62crvUo9_6oQ9u3ZmarhkLaxZv_E" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:3r_XEkPAZh4LnB8I-To3JqqbQ4i61xk0SxZdISsn7bA" + } + } + ], + "fullUrl" : "urn:uuid:73016128-8749-5e45-8f7e-4233ad7127e9", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:3r_XEkPAZh4LnB8I-To3JqqbQ4i61xk0SxZdISsn7bA" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:2-2QazrhiBc7l7nA-KUw6kuhhKZfGEg1yZFJESCi2YQ" + } + } + ], + "fullUrl" : "urn:uuid:42665bc4-47cb-5662-ba20-1bd901bb3d5f", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:2-2QazrhiBc7l7nA-KUw6kuhhKZfGEg1yZFJESCi2YQ" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:73016128-8749-5e45-8f7e-4233ad7127e9" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:629bHl09cB2y8LG2fmd6HTa4uEw7YKTDeSnKN8rmfHY" + } + } + ], + "fullUrl" : "urn:uuid:4d099c8a-ad19-5a18-92e2-2072fe51f68d", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:42665bc4-47cb-5662-ba20-1bd901bb3d5f" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:UhqDpMunyA3OXTgy0e8OBXov4_RG9AXVMh4HAlwurJ8" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:5b585439-a9f5-5e29-b7ff-a546e0635440" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:7" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-no-time-zone.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-no-time-zone.json new file mode 100644 index 000000000..8055c1fc5 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-no-time-zone.json @@ -0,0 +1,446 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:vCDqSflQHgz7jeLSR_7WHPevQwOvW9qnXvckGUYvOaY" + } + } + ], + "fullUrl" : "urn:uuid:1ac05d36-060f-53df-97fb-6ca1ab8de654", + "resource" : { + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "device" : { + "reference" : "urn:uuid:df68da13-4433-597b-896a-176c093317d2" + }, + "effectiveDateTime" : "2026-08-17T22:30:00Z", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:0zvvrYgO_mi1B22durhuNzGRxVIW9uAPUGtiTBFnv-A" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:vCDqSflQHgz7jeLSR_7WHPevQwOvW9qnXvckGUYvOaY" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:I8UY96JTgqqF6G5NWXYYsND2CXyksyvVFbVsKrlNRWM" + } + } + ], + "fullUrl" : "urn:uuid:df68da13-4433-597b-896a-176c093317d2", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:I8UY96JTgqqF6G5NWXYYsND2CXyksyvVFbVsKrlNRWM" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:hCY4NQI_y6em5f_c43aPg6ECZrQDhxDQiqnoaqLOwWg" + } + } + ], + "fullUrl" : "urn:uuid:a8957587-88ce-5387-a9ba-0c1622bba019", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:hCY4NQI_y6em5f_c43aPg6ECZrQDhxDQiqnoaqLOwWg" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:wDQFeU4CY30y5RpPKQiQUK8_RQKJcUTVKYSfYN4eqhs" + } + } + ], + "fullUrl" : "urn:uuid:7bff30cd-6c10-54f7-805d-2150d3ac9918", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:wDQFeU4CY30y5RpPKQiQUK8_RQKJcUTVKYSfYN4eqhs" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:a8957587-88ce-5387-a9ba-0c1622bba019" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:GFd_R7SNAh-SogYlMxYnPYO7W_LvACxC2mrLp1DbbBs" + } + } + ], + "fullUrl" : "urn:uuid:91cd3248-28d0-5bca-9c86-b48306285c0a", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:7bff30cd-6c10-54f7-805d-2150d3ac9918" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:0zvvrYgO_mi1B22durhuNzGRxVIW9uAPUGtiTBFnv-A" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:1ac05d36-060f-53df-97fb-6ca1ab8de654" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:5" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-recording-device.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-recording-device.json new file mode 100644 index 000000000..263bbdbf0 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-recording-device.json @@ -0,0 +1,454 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:3wO9C7SmhNLOOZgffPpC6pIu26L0vD3shgAFI9kS6To" + } + } + ], + "fullUrl" : "urn:uuid:6ce106db-c3e7-594f-8687-ab19bf2675b6", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "device" : { + "reference" : "urn:uuid:71e2da36-119b-5cf4-be1d-0e67a02fb6b7" + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:JFAIjt2Ir1Tf0wu6Xx4ZszaDG0SAP2-NqCXKCM5HVY0" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:3wO9C7SmhNLOOZgffPpC6pIu26L0vD3shgAFI9kS6To" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:B6XeXLL-VmnoUgxJ0YIai5QKNbptYLlffp_CSMmUa0I" + } + } + ], + "fullUrl" : "urn:uuid:71e2da36-119b-5cf4-be1d-0e67a02fb6b7", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:B6XeXLL-VmnoUgxJ0YIai5QKNbptYLlffp_CSMmUa0I" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:sVL5imAUtEv8qkZ5y14b-DAePRaI8_AMMlxR1rfUxEI" + } + } + ], + "fullUrl" : "urn:uuid:56f9ca1f-1f3c-5943-bdfb-b5679bc11aa2", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:sVL5imAUtEv8qkZ5y14b-DAePRaI8_AMMlxR1rfUxEI" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:j9B5fK3LDpZaCHzQoUHSuKOaAaHQ-ZjC_KXMe6gcakI" + } + } + ], + "fullUrl" : "urn:uuid:da9a946d-cf2e-5f80-9f53-c00eacd6bf6d", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:j9B5fK3LDpZaCHzQoUHSuKOaAaHQ-ZjC_KXMe6gcakI" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:56f9ca1f-1f3c-5943-bdfb-b5679bc11aa2" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:clVl8Y9AOT95NodKnbssmvet5zx3B8hfWQZd55unQDA" + } + } + ], + "fullUrl" : "urn:uuid:88777b9b-be93-5d90-a27d-823b23543bf7", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:da9a946d-cf2e-5f80-9f53-c00eacd6bf6d" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:JFAIjt2Ir1Tf0wu6Xx4ZszaDG0SAP2-NqCXKCM5HVY0" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:6ce106db-c3e7-594f-8687-ab19bf2675b6" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:3" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-study.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-study.json new file mode 100644 index 000000000..0cb5506ff --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heart-rate-study.json @@ -0,0 +1,458 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:9AcCZ7kciJyqy-mbjXSvTnM0QVKPlBya3mZDyiJpyVs" + } + } + ], + "fullUrl" : "urn:uuid:4336f7f4-3650-5a6d-9f98-394e2545f9b7", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + }, + { + "url" : "http://hl7.org/fhir/StructureDefinition/workflow-researchStudy", + "valueReference" : { + "reference" : "urn:uuid:cf0cc8ee-e261-5412-bebb-4b27d6906e72", + "type" : "ResearchStudy" + } + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:v1GmcePBvnFaDej_47daIYdo0ocOVGqxgmBNuoK8oR0" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:9AcCZ7kciJyqy-mbjXSvTnM0QVKPlBya3mZDyiJpyVs" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:research-study:0:g2hVN5FPt02ErV-GJJE2KNM-ZVNuZIYExNoTojrgRWg" + } + } + ], + "fullUrl" : "urn:uuid:cf0cc8ee-e261-5412-bebb-4b27d6906e72", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/researchstudy", + "value" : "study-a" + } + ], + "protocol" : [ + { + "reference" : "urn:uuid:f3fa28b4-22ec-53ee-b6ab-f652b502f278" + } + ], + "resourceType" : "ResearchStudy", + "status" : "active" + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:plan-definition:0:vsD2OI6dQb-MubJBowTvzuMp-UDrCfbOvYw6Ena1JNw" + } + } + ], + "fullUrl" : "urn:uuid:f3fa28b4-22ec-53ee-b6ab-f652b502f278", + "resource" : { + "resourceType" : "PlanDefinition", + "status" : "active", + "url" : "https://study.example.org/PlanDefinition/study-a", + "version" : "1" + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:research-subject:0:JTOvEu7YnYXGsaZzam7DRASOJZLQFnvMvifAJbw1e9Q" + } + } + ], + "fullUrl" : "urn:uuid:fd465684-e608-5933-bdf3-b42b183943cb", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/researchsubject", + "value" : "enrollment-study-a" + } + ], + "individual" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "resourceType" : "ResearchSubject", + "status" : "on-study", + "study" : { + "reference" : "urn:uuid:cf0cc8ee-e261-5412-bebb-4b27d6906e72" + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:kNJjLhZhj68v9q-BdykucZb6Wyo7k0WDeSAfuRdYxUk" + } + } + ], + "fullUrl" : "urn:uuid:7ae4f6db-bd17-5949-9eb4-b0c6271023b0", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:kNJjLhZhj68v9q-BdykucZb6Wyo7k0WDeSAfuRdYxUk" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:5tCTZ0031RQubXS4aMy0Da4_GfwUXlOrH5vbOfb1sUs" + } + } + ], + "fullUrl" : "urn:uuid:0a198ca0-f3ab-58c0-9fb4-90f84261bcc9", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:5tCTZ0031RQubXS4aMy0Da4_GfwUXlOrH5vbOfb1sUs" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:7ae4f6db-bd17-5949-9eb4-b0c6271023b0" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:qzsd6GqllC-7rLPEkX4CHZDVHsJY2OLvtasPNdBE8m4" + } + } + ], + "fullUrl" : "urn:uuid:480c6348-7ae6-545c-b048-1041f1e18607", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:0a198ca0-f3ab-58c0-9fb4-90f84261bcc9" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:v1GmcePBvnFaDej_47daIYdo0ocOVGqxgmBNuoK8oR0" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:4336f7f4-3650-5a6d-9f98-394e2545f9b7" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:2" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heartbeat-series.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heartbeat-series.json new file mode 100644 index 000000000..40f79a7b1 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heartbeat-series.json @@ -0,0 +1,612 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:3pO4DxCljd8pc9tNwzRisHLlIAucD_p24zsWHiYObLI" + } + } + ], + "fullUrl" : "urn:uuid:1628b7cd-7e64-5b1d-9318-de22a56a938c", + "resource" : { + "author" : [ + { + "reference" : "urn:uuid:61196f1c-10d4-56f5-8096-cb4c72f9b8ff" + }, + { + "reference" : "urn:uuid:a459949b-1d5b-57b5-96fa-16f81714298c" + } + ], + "content" : [ + { + "attachment" : { + "contentType" : "text/csv", + "data" : "dGltZXN0YW1wLHByZWNlZGVkQnlHYXAKMTc4NzAwNTgwMCwwCjE3ODcwMDU4MDAuODQsMAoxNzg3MDA1ODAxLjcxLDEK", + "hash" : "PznINcuYWCKX6a0UnspSBwERECs=", + "size" : 69, + "title" : "Heartbeat series beat intervals" + }, + "format" : { + "code" : "beat-interval-series", + "system" : "https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format" + } + } + ], + "date" : "2026-08-17T23:30:00Z", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKDataTypeIdentifierHeartbeatSeries" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:2k0tuZSOvNmO-Sba43w3uUkdUrfF1yb46WU0ZXNL7sw" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:3pO4DxCljd8pc9tNwzRisHLlIAucD_p24zsWHiYObLI" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1", + "type" : { + "coding" : [ + { + "code" : "source-artifact", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:0m696r-5hPLWnq6y0mjPQ3UXXMj39DkqI0cXJQxSS6Q" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-recording-document", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-recording-document" + ] + }, + "resourceType" : "DocumentReference", + "status" : "current", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "type" : { + "coding" : [ + { + "code" : "beat-interval-series", + "system" : "https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format" + } + ] + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:S-28g42BNOx3dfVHaeYjmh1HvdwjwAa1BcT_IGnBekI" + } + } + ], + "fullUrl" : "urn:uuid:61196f1c-10d4-56f5-8096-cb4c72f9b8ff", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:S-28g42BNOx3dfVHaeYjmh1HvdwjwAa1BcT_IGnBekI" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:2EDaYUDR-dDUwtxTee763paCaDWqKSP8MboszwuQrVs" + } + } + ], + "fullUrl" : "urn:uuid:d92b490d-2a2b-551f-b17a-d6b66396b109", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:2EDaYUDR-dDUwtxTee763paCaDWqKSP8MboszwuQrVs" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:GhSmTTVkJf9pdJIvV5sSn0lepGBfCQO-hA0HgQ5_zgI" + } + } + ], + "fullUrl" : "urn:uuid:a459949b-1d5b-57b5-96fa-16f81714298c", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:GhSmTTVkJf9pdJIvV5sSn0lepGBfCQO-hA0HgQ5_zgI" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:d92b490d-2a2b-551f-b17a-d6b66396b109" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Gm4hRTUp_vyKqlJoLR1QaMBMYnADSoLLNT26d8KscYA" + } + } + ], + "fullUrl" : "urn:uuid:35f19e6b-6e60-5b6c-b203-d4ac0dce18aa", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Gm4hRTUp_vyKqlJoLR1QaMBMYnADSoLLNT26d8KscYA" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "iPhone17,1", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "26.1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:fKbOYBSJFXz6oCcdT3U15J88O4mc-9SuexoDJ5mI6Wc" + } + } + ], + "fullUrl" : "urn:uuid:f72582bb-3a7c-5255-808c-cdba39fd1a84", + "resource" : { + "deviceName" : [ + { + "name" : "Example Writer", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:fKbOYBSJFXz6oCcdT3U15J88O4mc-9SuexoDJ5mI6Wc" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.example.writer" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:35f19e6b-6e60-5b6c-b203-d4ac0dce18aa" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "42" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:XhwlvRTJuxRNCMkujvlJIVBV2qNofAA7OE114qan3-s" + } + } + ], + "fullUrl" : "urn:uuid:788d39f2-4d35-55e3-a603-c312e815acc7", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:a459949b-1d5b-57b5-96fa-16f81714298c" + } + } + ], + "entity" : [ + { + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "author", + "display" : "Author", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:f72582bb-3a7c-5255-808c-cdba39fd1a84" + } + } + ], + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:2k0tuZSOvNmO-Sba43w3uUkdUrfF1yb46WU0ZXNL7sw" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:1628b7cd-7e64-5b1d-9318-de22a56a938c" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:62" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/insulin-delivery-bolus.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/insulin-delivery-bolus.json new file mode 100644 index 000000000..3307a1417 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/insulin-delivery-bolus.json @@ -0,0 +1,371 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:TpBGu0U76ckj1qt_PEhc4Y4e3yL-XWR3LSHRUjGCaoY" + } + } + ], + "fullUrl" : "urn:uuid:ad4e084a-827a-5932-a483-d147c721c333", + "resource" : { + "code" : { + "coding" : [ + { + "code" : "insulin-delivery", + "display" : "Insulin delivery", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement" + } + ] + }, + "component" : [ + { + "code" : { + "coding" : [ + { + "code" : "HKInsulinDeliveryReason", + "display" : "Insulin Delivery Reason", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-metadata-key" + } + ] + }, + "valueCodeableConcept" : { + "coding" : [ + { + "code" : "bolus", + "display" : "Bolus", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-insulin-delivery-reason" + } + ] + } + } + ], + "effectivePeriod" : { + "_end" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "_start" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "end" : "2026-08-17T15:30:00-07:00", + "start" : "2026-08-17T15:30:00-07:00" + }, + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierInsulinDelivery" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:PzIlGWciVIW4OHEiu8JrU-mh3ZGK00TQuM9Wkym6v8M" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:TpBGu0U76ckj1qt_PEhc4Y4e3yL-XWR3LSHRUjGCaoY" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-insulin-delivery" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "[iU]", + "system" : "http://unitsofmeasure.org", + "unit" : "IU", + "value" : 2.5 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:w7hAe7eU9F2Pza8KNvJ_tKl0CUu0qjHwtsURgcCsjws" + } + } + ], + "fullUrl" : "urn:uuid:3782a788-c4f8-585d-b1fd-9d30db778ec0", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:w7hAe7eU9F2Pza8KNvJ_tKl0CUu0qjHwtsURgcCsjws" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:qupt7iGRe28OC6Jupya0EqDtFtrnt5OguqDm_apV6Zc" + } + } + ], + "fullUrl" : "urn:uuid:ec647088-2030-550f-847f-dcf99307952f", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:qupt7iGRe28OC6Jupya0EqDtFtrnt5OguqDm_apV6Zc" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:3782a788-c4f8-585d-b1fd-9d30db778ec0" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:vu5arWqaCxUrwcmwkgZSUghepsegIdsaBCDax4rwPiw" + } + } + ], + "fullUrl" : "urn:uuid:87f3b34a-18d9-5ed8-a367-6b05b0812c9c", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:ec647088-2030-550f-847f-dcf99307952f" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:PzIlGWciVIW4OHEiu8JrU-mh3ZGK00TQuM9Wkym6v8M" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:ad4e084a-827a-5932-a483-d147c721c333" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:12" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/native-identifier-disclosure.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/native-identifier-disclosure.json new file mode 100644 index 000000000..a3ada1141 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/native-identifier-disclosure.json @@ -0,0 +1,610 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:KoUX5V4z_JdDxLoeOGW6Eafx0ddWi_LxZpYonBlqkAk" + } + } + ], + "fullUrl" : "urn:uuid:a3f78dc4-67e7-561a-a4b8-0238dfe912b9", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "device" : { + "reference" : "urn:uuid:c539f699-f154-5ead-8bc3-ba4525469797" + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:DOmu1Geffa33EKF3i27jlvr65e2inMwxS3Pe-pT2WSc" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:KoUX5V4z_JdDxLoeOGW6Eafx0ddWi_LxZpYonBlqkAk" + }, + { + "system" : "https://study.example.org/fhir/NamingSystem/healthkit-store", + "value" : "3a7e5c10-0000-4000-8000-000000000028" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:VEwF9D7eejNY_33KeNLiwpSRgNpN8FlyJ9L8StvEqi4" + } + } + ], + "fullUrl" : "urn:uuid:c539f699-f154-5ead-8bc3-ba4525469797", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:VEwF9D7eejNY_33KeNLiwpSRgNpN8FlyJ9L8StvEqi4" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:WO4IFlfT469FR97zUB8CsMPAQbSVxbH2rxbozB__wuk" + } + } + ], + "fullUrl" : "urn:uuid:d07b38c0-a05c-5e19-8f92-6cd763581b41", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:WO4IFlfT469FR97zUB8CsMPAQbSVxbH2rxbozB__wuk" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:T2_bfXjbfI6JRcEb_FRD0PZb19zel8PG8pS3bMWy25E" + } + } + ], + "fullUrl" : "urn:uuid:f0c2b236-bdae-5da3-bd65-832cfb6a858d", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:T2_bfXjbfI6JRcEb_FRD0PZb19zel8PG8pS3bMWy25E" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:d07b38c0-a05c-5e19-8f92-6cd763581b41" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:6_cJPfzFz0pYAYN9M-RGyPz5Gcabdpjvh7xr3Q2anfM" + } + } + ], + "fullUrl" : "urn:uuid:51571f65-d367-5848-9557-f958f42357bc", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:6_cJPfzFz0pYAYN9M-RGyPz5Gcabdpjvh7xr3Q2anfM" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "iPhone17,1", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "26.1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:c8W0vHmQMLvMGY5CqBiah9DLz-rT454GqeZqtuLJrbU" + } + } + ], + "fullUrl" : "urn:uuid:647ca0a1-1154-58d5-bb7c-a880387bbbcb", + "resource" : { + "deviceName" : [ + { + "name" : "Example Writer", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:c8W0vHmQMLvMGY5CqBiah9DLz-rT454GqeZqtuLJrbU" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.example.writer" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:51571f65-d367-5848-9557-f958f42357bc" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "42" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:PBk0zDcyGj78ylfmvtm3JfwE60NUf4UUN8j3FoGbE_0" + } + } + ], + "fullUrl" : "urn:uuid:8917710a-f76d-56c6-b18f-77f41a55f2c3", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:f0c2b236-bdae-5da3-bd65-832cfb6a858d" + } + } + ], + "entity" : [ + { + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "author", + "display" : "Author", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:647ca0a1-1154-58d5-bb7c-a880387bbbcb" + } + } + ], + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:DOmu1Geffa33EKF3i27jlvr65e2inMwxS3Pe-pT2WSc" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:a3f78dc4-67e7-561a-a4b8-0238dfe912b9" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:40" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json new file mode 100644 index 000000000..33446d279 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json @@ -0,0 +1,2650 @@ +{ + "blood-pressure-correlation" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:7c02d4b0-6930-54ba-abdc-b13fddf9d455", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:vLdiWMfbEdPYj0ZhB2yGpzKc4LWgjn8AKpfulR4al70", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:HJhsGCU0HGa7Aqd5tovsAlqoRUbEanhnWhyg2YvlLYs" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:d2cd468b-2987-5199-b4c0-48c5eec53859", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:CQ0jODSC-bNYoRR0_AHtgC4Q_JizgYcUY_y9hjljmog", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:8f81e542-3dfd-5054-b22f-d53c0823a33a", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:7-32qRTb-NQabioMS2xoogyed9aSAajDlWKB6A3KbQk" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:d0c7ce86-5213-531a-ad32-cb529f53e124", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:67Lhzk6u228PXAzIdweio4NGJJD3oTKloIqbVqUReKw", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:523d31e8-ce2e-5977-8f14-426a81e6ca23", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "body-mass-user-entered" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-method" + ], + "fullUrl" : "urn:uuid:fb2b9e67-66d9-59c7-ad40-ea775fe3b868", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:9CgPOpef1tVsmk6EJLj4bHDFqZjlSP3_YFNbUf3ytO0", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:F6fP40xYTCErdBIkNK4EIX6TSvP-dAfEc6HiM5eL0zI" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:73f08f07-d15f-56d8-9e05-2284b4257115", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:bfAm_8-MNzij0e97hfE7pzZS1j6jMFvxhdqjxzJ4J8A" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:60480b75-8e2f-5965-8304-cbc631ebf103", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:JuZ6_LIOGPqBp4ARA79_zsVhTPr1T7_1_9I13pImZlE", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:b1cc275d-98bd-599c-8ed3-1199de610a33", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "bundled-patient-subject" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:650fea1f-8ed4-5da7-9ae4-5818aa9b9723", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:kZgmCleuRbCorIFh8TYwlJKZ0G7xxJjPPILaB_ofGXI", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:bTcTOBWHOO59CuWRcxRiszcArYdSNMtMRRDeYq0ofYI" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:d4ed1c3e-f2d8-5934-8b30-f763563944d5", + "identifiers" : [ + "-|https://grovealliance.org/fhir/testing/identifiers/patient|example" + ], + "resourceType" : "Patient" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:ca0e3e67-0999-5780-84db-8d7124905621", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:obS6ZZln0e8HpGaJGSLbhDju94K0R1XKF-Gzbvjo_wI", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:4dae8507-5cc2-5c70-97cf-e1fe97528ec6", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:R68gsXOmise6Dzaom-ZmFVQ0qVflQmxfCRI7OL4G_KI" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:179aa15e-38a6-520d-9db2-6f53180ce523", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:V8y_3IHBJVsf5HzFrCfRBGyrYLvN-eCGxV0iqOnBt5c", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:27bc90ae-3192-5159-990d-4764c5569192", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:7zKG772wpnhNjRFdQUlSF2bgzCLS0psSYI8jDlCBDmI" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:dafff25f-7b2a-50f1-8062-35eaaa6d3c23", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:NEec450y0sraR7xbqWgH3yVUfbenpZd3_EXE6szNmrM", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:be2a33d7-8e5f-5fa9-9a3d-b5a0ee9a747c", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "clinical-document" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:522e0b85-6287-5760-9cdb-8cbe87ee4011", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:1KLEBhU35GE7bcLZ8_vWmici5Op3CrzR_No7MGJvD4o", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:keBDoyNksAXgYsWVUD4BFLHyipaDAc9Ycnhbv0SQXTY", + "source-artifact|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1|v0:test:1:GqFmAyiQxxDL7NfpD2FTjh-dDA8oHplVEJad0faE69Y" + ], + "resourceType" : "DocumentReference" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:450fe019-fd6b-5b19-b07c-37ca7e7ffde8", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:CQjW7k2FMuRv7NCI2j0QYDu_wzuNn3VwjikNsSHBUc8" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:5cc49e86-4d50-5d36-8c05-1f2401721cd0", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:Jb69oEAStFO5k0ZHlgVZ7QgOQfL-fKyMvP0WcEp2jek", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:17062a17-1106-5adb-9c5e-f2d9e93ce341", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "electrocardiogram" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period" + ], + "fullUrl" : "urn:uuid:71eb02d9-992e-50b1-b859-4988b669ea26", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:hIzISl6FuqMWdHZcjP-B2_ksukup6BnRgGqsPPiVe6g", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:oUFZxFHM9ZPeflL9v9vdkmv-K_UDjOb_bH0DeVFFY-k" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:ef688b88-8189-5ca7-aaca-951235dc4daf", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:hIzISl6FuqMWdHZcjP-B2_ksukup6BnRgGqsPPiVe6g", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:ayjux3kQuPNZ8LpeJo_AS0R2Z_mfSJjlyS2kQBrtfPI" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:74b08d9e-cbc8-50d1-9680-4c3f9286f1f3", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:9EW_T3EzD9L34WmvN-K2Dy28CU_HykiShypagj0B3rs", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:1319dc48-a2ee-572f-b3b4-3b5fe7104a85", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:WWpRG50Fmgy4qqc6KCNlXGGxAgh6M-XyMRWOZ4rs6Gc" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:fd6347b4-6143-5ace-b626-ce0e1e0e57fe", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:VDIX5JqXoM-Le5Rs8unycEU6vlLw3FS4A2ENFt-2y80", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:659ba41a-b773-5177-9923-8a596c45de30", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:CqlhnFqMlGAci4vaQkCBgBeUJF9aA3J1bjjEXCs6pNE" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:ac9e967e-1606-58e5-8a33-72e6f7e602af", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:ZhPvEZjeAyTc7gzk7uluiB_0SIAc29eOtaofueV0kCs", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:68e0a782-d8a1-5e27-aaa9-b0c272c89904", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "electrocardiogram-symptom-companion" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:4f80da53-e7aa-5bb5-b3b6-f7c857d6a562", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:HZJlYgBiY4WzfqtgcMLKxZqzvSOU_R6MA0SzsEMQaqc", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:JMuXnGeBq7p_tQuIWauSJ__Y2BZk3e8klW8tV6TU-t4" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:66083dcb-56e4-5d41-bf87-ab0232e14a45", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:bdrO0Z5G0evQXWD7Z9o75aMzBVv06xTBr-7X5oCWkkI", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:957b2550-1d36-57ef-a729-adb23cbbdf6d", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:UEL4cLZZ2F65r2sT74r9y5dQLTe88TTy5V_Q8Od7T5w" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:87b995e3-4383-5c86-958a-6cac67c2b805", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:8IIPpVa6RgGzsLLFmOJsCgVkalyzllLnX09IZzPiXtM", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:342152e5-0fa1-578f-ae92-0d3bc245ea35", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:ev4pSJxtJxgCn6I6NDCdnbGMIjNZ8UeRnKZ37mpcoiI" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:7cdf03d0-e248-5b92-901d-299e17845605", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:SsFGcQUFXzymFU5DlqvKSv5JIcmRgG5ElFKAzjodj_8", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:43f1180e-d7c0-5797-9e48-0c4313172870", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "electrocardiogram-with-symptom" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period" + ], + "fullUrl" : "urn:uuid:0786bc40-f9fe-59ec-b7a2-9d26bb724885", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:-sxIw2zn3pl-JMISV5kprDK_i02tIT0Ct69amwTw6qg", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:aUWZCMJyOEYVCVaXUSSdpkIn1drfk6ajkMCLpT6mtBs" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:e6dcf13b-2eb2-5ba1-912d-cf8e9b8bf45b", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:-sxIw2zn3pl-JMISV5kprDK_i02tIT0Ct69amwTw6qg", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:U8O093yT3aixzE4WxrTS8T-opQPH8CkYgWelojPulPg" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:09445bfa-2f2d-5729-87e3-276e1710ac51", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:TZMowVmB-5la9zz95eOceigG1lda9_5sQC9wrGPHLEU", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:17155fd0-ad6a-52c4-a946-4468106caffa", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:N-ePkunWLS3fcvs9rDd5uh5ltmoRt7EmotuxWRTo7vA" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:219bc452-900a-5a4d-8777-ecbfc1f6a85f", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:BYBvIKW5wu4S6evy4SPZQOFB37YD2y8s3Hcg6E6_KE0", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:08844702-36cb-57ff-b249-2b1b843fb79f", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:s8buBEyG4yRzKd2hA02jUKfwT2IN5N5psYD2moM7mb4" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:965a804c-2f33-5fe0-ae1e-a4a328007269", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:7oVlArgLSpX9m-sICbkampE5_6rdy4EpAz-xyYWON1o", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:8a8b3433-b274-5da2-8db1-7c0d4004f7ec", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "gateway-application-role" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "http://hl7.org/fhir/StructureDefinition/observation-gatewayDevice" + ], + "fullUrl" : "urn:uuid:a88e060e-ec7c-5ec0-8b0e-6b7356e7fa9e", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:JBRlTi02jeW9eRSv9XELCh4dhoYzM9dKYgs7qjnt0_g", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:qDMUHRvr7xVoEjlMqF4oQpjiXZPTRmaawKpTmh0hxZM" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:04f063a3-bc62-545f-a0b8-11df9af133d2", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:WDBinr5w7PcvcaRoBNjWHPRhjGyOqM4yC41LwfI3Z24", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:269b221d-c646-53f1-aa9d-915c11263c4e", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:n2EmlS9mA64HvuKSRZvPQ_DLqUHhITDmpPeSxuo31Qc" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:86793a3d-e936-5a9e-8221-13afab7db244", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:qQviYoSoPxQMtwJNPGZ5o7kjf2fl3QdHBcnPIshRxho", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:3ec42d04-7eae-5c23-82c4-e94e197f0689", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:o2qpZsBSsRdBi4QW3djT5K4Nx6B0i87AIAloYcV7kBQ", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|com.example.cuff" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:48aeeb20-6643-5b41-b3a3-44093a548f15", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:08kGbsvdtUqZumirucowZS9ePH45abfoM5O4nNX7rkk" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:480efa67-eb12-5f15-92ba-fbc30cf24d40", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:J9lvvDAXkS_dbdj52mxPi9OlB8TwcLXwadZ2GWu6m4Q", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:134073a9-d5de-5dd9-abaf-6b7bb226f0a5", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "gateway-role" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "http://hl7.org/fhir/StructureDefinition/observation-gatewayDevice" + ], + "fullUrl" : "urn:uuid:dbafa993-ba4f-51e0-ad7d-d796ddd5ef67", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:McX70VJJ-8FCgv1530lWhJkyrzUfPpP0aF8zkUnT1j8", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:y0zwisf7fEMxJ5H1xFk6erxnBpS828ph8teZOqYhPZA" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:ec2cb5c9-19da-5d18-bb0e-85d60b7ddb81", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:9ySy4ypKV6MKykXXkoertO-a3k5upQix_qDPvkaZea0", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:e35a840b-f0fc-5a54-bf90-8fee85372598", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:15QiZ156dS5FCTIE4qwxG8XTq4xdjEkbTo4YplOsQWo" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:4a209379-2c63-56e3-9767-a3c44f6b3b90", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:pU1MJcL1Jj23OM_Lj2WfKnbPCczTrVqlBeup_rEzjas", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:1f896505-6996-55e4-8231-8412a4c864a8", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:gL3lSNl7EYteXp70F6laHYwj023D9L4lpXWNgHKH-ds" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:1fb8e303-b58a-5107-ac2d-9ddced20bb00", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:qYBO4DwuNe0zTKt3vV2rd6GhfJZ_a6meCVdUGWQ8Aqo", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:ded34666-95a9-5629-9a8a-a646a65d7949", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "heart-rate-device-without-unit-token" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:7a259769-1a74-5890-9a8e-23bfd25b9ec2", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:bPp6yNIw-P0yHmagH5lycYA4UrqiKUpUuNEpILTibp4", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:mqKBBlGQyKkNm_nQgCH3Gpyvvaea9nCO_EBIECecs40" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:ee821cbc-1292-5eb4-928b-40d31ca63779", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:IODV7uCVRUy8uwuwRj6vAt8ztpJqRxcifZkh1u8JvlQ" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:54dc5efd-613f-5b6b-b465-8d4f0ef2852d", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:Pa_emYvici83-idni_3JyQswXeUjZXEFuMOMTy4KPRg", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:c909f4f7-0a9b-5ceb-b215-26c878688fde", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + "mobile-omission.recording-device(Apple Watch)" + ] + }, + "heart-rate-interval" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:1e5229cf-7fd0-5b3e-b863-30715d61c524", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:4rxRgRPFMWMMdZjfm_6SU_15FbhtTaNWNdObFGoYFRg", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:alpiL3HSFzX615rQp5kgWJ1b3AnK4IeBNVo7QLA_yNU" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:c66db3b2-ae1f-5cc1-88ba-1c864c2367eb", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:t4bJSfVWvCGBHpnbCG2wbiVs5f1fJVa01BCH6IufXoQ" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:0cf2a54e-f04e-5f26-a122-c294493a0923", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:CsxkUTODH696XsMQgxN64nOFEeUxwN0xvHAEZfw0vKs", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:bc374b4f-e99a-5487-9194-f15e081f6cb4", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "heart-rate-minimal" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:43a60a20-f034-5ad7-9f00-f65aac29503c", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:QxmbFs_KgP8IGB0zSPXhCdpTD6t0M14cf7yY-d_SnD8", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:tfWplyF8loEu85zzoEd3najBmp1FgU9xJGD9Pka_-3E" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:a11ff194-13a8-5786-8fca-9848678e78d6", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:7CHu7jAo4aD4P_YJAGl7D2HoTu7jnFRqNgfxWygnOQ8" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:66d6c515-f557-52a5-bcaf-fe94b965f94b", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:2yoi5jK0yGmK7znYdA-VNwyn13nwyTvg63St3ZoMMMk", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:fd512c31-6e2a-5d5c-aab5-59631ebfb8d0", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + "mobile-omission.source-offset@Observation.effectiveDateTime" + ] + }, + "heart-rate-motion-context" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:5b585439-a9f5-5e29-b7ff-a546e0635440", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:UhqDpMunyA3OXTgy0e8OBXov4_RG9AXVMh4HAlwurJ8", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:3pyNyAsRSdh8eIJW6Mpn_15dioT3PgGTjhyKX-ZvTLY" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:3228e4b0-e429-538c-af60-19d75dccc91b", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:lslI_JP2D6DtsNS62crvUo9_6oQ9u3ZmarhkLaxZv_E", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:73016128-8749-5e45-8f7e-4233ad7127e9", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:3r_XEkPAZh4LnB8I-To3JqqbQ4i61xk0SxZdISsn7bA" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:42665bc4-47cb-5662-ba20-1bd901bb3d5f", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:2-2QazrhiBc7l7nA-KUw6kuhhKZfGEg1yZFJESCi2YQ", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:4d099c8a-ad19-5a18-92e2-2072fe51f68d", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "heart-rate-no-time-zone" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:1ac05d36-060f-53df-97fb-6ca1ab8de654", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:0zvvrYgO_mi1B22durhuNzGRxVIW9uAPUGtiTBFnv-A", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:vCDqSflQHgz7jeLSR_7WHPevQwOvW9qnXvckGUYvOaY" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:df68da13-4433-597b-896a-176c093317d2", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:I8UY96JTgqqF6G5NWXYYsND2CXyksyvVFbVsKrlNRWM", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:a8957587-88ce-5387-a9ba-0c1622bba019", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:hCY4NQI_y6em5f_c43aPg6ECZrQDhxDQiqnoaqLOwWg" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:7bff30cd-6c10-54f7-805d-2150d3ac9918", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:wDQFeU4CY30y5RpPKQiQUK8_RQKJcUTVKYSfYN4eqhs", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:91cd3248-28d0-5bca-9c86-b48306285c0a", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + "mobile-omission.source-offset@Observation.effectiveDateTime" + ] + }, + "heart-rate-recording-device" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:6ce106db-c3e7-594f-8687-ab19bf2675b6", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:JFAIjt2Ir1Tf0wu6Xx4ZszaDG0SAP2-NqCXKCM5HVY0", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:3wO9C7SmhNLOOZgffPpC6pIu26L0vD3shgAFI9kS6To" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:71e2da36-119b-5cf4-be1d-0e67a02fb6b7", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:B6XeXLL-VmnoUgxJ0YIai5QKNbptYLlffp_CSMmUa0I", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:56f9ca1f-1f3c-5943-bdfb-b5679bc11aa2", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:sVL5imAUtEv8qkZ5y14b-DAePRaI8_AMMlxR1rfUxEI" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:da9a946d-cf2e-5f80-9f53-c00eacd6bf6d", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:j9B5fK3LDpZaCHzQoUHSuKOaAaHQ-ZjC_KXMe6gcakI", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:88777b9b-be93-5d90-a27d-823b23543bf7", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "heart-rate-study" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "http://hl7.org/fhir/StructureDefinition/workflow-researchStudy" + ], + "fullUrl" : "urn:uuid:4336f7f4-3650-5a6d-9f98-394e2545f9b7", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:v1GmcePBvnFaDej_47daIYdo0ocOVGqxgmBNuoK8oR0", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:9AcCZ7kciJyqy-mbjXSvTnM0QVKPlBya3mZDyiJpyVs" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:cf0cc8ee-e261-5412-bebb-4b27d6906e72", + "identifiers" : [ + "-|https://grovealliance.org/fhir/testing/identifiers/researchstudy|study-a" + ], + "resourceType" : "ResearchStudy" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:f3fa28b4-22ec-53ee-b6ab-f652b502f278", + "identifiers" : [ + + ], + "resourceType" : "PlanDefinition" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:fd465684-e608-5933-bdf3-b42b183943cb", + "identifiers" : [ + "-|https://grovealliance.org/fhir/testing/identifiers/researchsubject|enrollment-study-a" + ], + "resourceType" : "ResearchSubject" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:7ae4f6db-bd17-5949-9eb4-b0c6271023b0", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:kNJjLhZhj68v9q-BdykucZb6Wyo7k0WDeSAfuRdYxUk" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:0a198ca0-f3ab-58c0-9fb4-90f84261bcc9", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:5tCTZ0031RQubXS4aMy0Da4_GfwUXlOrH5vbOfb1sUs", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:480c6348-7ae6-545c-b048-1041f1e18607", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "heartbeat-series" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:1628b7cd-7e64-5b1d-9318-de22a56a938c", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:2k0tuZSOvNmO-Sba43w3uUkdUrfF1yb46WU0ZXNL7sw", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:3pO4DxCljd8pc9tNwzRisHLlIAucD_p24zsWHiYObLI", + "source-artifact|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1|v0:test:1:0m696r-5hPLWnq6y0mjPQ3UXXMj39DkqI0cXJQxSS6Q" + ], + "resourceType" : "DocumentReference" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:61196f1c-10d4-56f5-8096-cb4c72f9b8ff", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:S-28g42BNOx3dfVHaeYjmh1HvdwjwAa1BcT_IGnBekI", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:d92b490d-2a2b-551f-b17a-d6b66396b109", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:2EDaYUDR-dDUwtxTee763paCaDWqKSP8MboszwuQrVs" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:a459949b-1d5b-57b5-96fa-16f81714298c", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:GhSmTTVkJf9pdJIvV5sSn0lepGBfCQO-hA0HgQ5_zgI", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:35f19e6b-6e60-5b6c-b203-d4ac0dce18aa", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:Gm4hRTUp_vyKqlJoLR1QaMBMYnADSoLLNT26d8KscYA" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:f72582bb-3a7c-5255-808c-cdba39fd1a84", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:fKbOYBSJFXz6oCcdT3U15J88O4mc-9SuexoDJ5mI6Wc", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:788d39f2-4d35-55e3-a603-c312e815acc7", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "insulin-delivery-bolus" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:ad4e084a-827a-5932-a483-d147c721c333", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:PzIlGWciVIW4OHEiu8JrU-mh3ZGK00TQuM9Wkym6v8M", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:TpBGu0U76ckj1qt_PEhc4Y4e3yL-XWR3LSHRUjGCaoY" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:3782a788-c4f8-585d-b1fd-9d30db778ec0", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:w7hAe7eU9F2Pza8KNvJ_tKl0CUu0qjHwtsURgcCsjws" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:ec647088-2030-550f-847f-dcf99307952f", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:qupt7iGRe28OC6Jupya0EqDtFtrnt5OguqDm_apV6Zc", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:87f3b34a-18d9-5ed8-a367-6b05b0812c9c", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "native-identifier-disclosure" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:a3f78dc4-67e7-561a-a4b8-0238dfe912b9", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:DOmu1Geffa33EKF3i27jlvr65e2inMwxS3Pe-pT2WSc", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:KoUX5V4z_JdDxLoeOGW6Eafx0ddWi_LxZpYonBlqkAk", + "-|https://study.example.org/fhir/NamingSystem/healthkit-store|3a7e5c10-0000-4000-8000-000000000028" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:c539f699-f154-5ead-8bc3-ba4525469797", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:VEwF9D7eejNY_33KeNLiwpSRgNpN8FlyJ9L8StvEqi4", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:d07b38c0-a05c-5e19-8f92-6cd763581b41", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:WO4IFlfT469FR97zUB8CsMPAQbSVxbH2rxbozB__wuk" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:f0c2b236-bdae-5da3-bd65-832cfb6a858d", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:T2_bfXjbfI6JRcEb_FRD0PZb19zel8PG8pS3bMWy25E", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:51571f65-d367-5848-9557-f958f42357bc", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:6_cJPfzFz0pYAYN9M-RGyPz5Gcabdpjvh7xr3Q2anfM" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:647ca0a1-1154-58d5-bb7c-a880387bbbcb", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:c8W0vHmQMLvMGY5CqBiah9DLz-rT454GqeZqtuLJrbU", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:8917710a-f76d-56c6-b18f-77f41a55f2c3", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "repository-ids-on-every-node" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:bedd22e2-64c2-52eb-ad12-4fcd8b2f7116", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:QzF2mgRu5BLZ1u7h-O0-xttOmmOYiqgiZWnPoFh6aSo", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:dFzIvPfelFY7OsDcfM18IY5G1nJgn02BNIHXScSWKsQ" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:8068aec8-be51-54d9-af86-bda3b55b2da9", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:eB8Gf-LhSAaBL_oxV6y1Zodqv3uXKnvm67j60gXtEVg", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:3870e66b-7993-5249-b08d-a8ee4ab511e1", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:uYtmRqrnSdKKb0_BQdY5Bai87GbCUpRwjurAtvoOA-8" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:2d1d232a-dce0-5234-9f70-e6f1f57a06d2", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:N0D78V87eBkedJrHAL-1npBxK_OQ7ycRrVYu0-FcfMM", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:6835b79a-e720-5d06-8df2-376fc5675c58", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:dG1NzkNlb5umEYXyrGnJZ9ModYp454veeMqiqWJOAPc" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:676da85f-7976-593f-8308-df804c106a16", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:s_Cee-Bm1PdPanXpAhVVnuPXTAgty-n1BHE5QPmtoVQ", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:f9387192-08d6-56d5-929b-57821c1a17b0", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "retraction-blood-pressure" : { + "entries" : [ + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:1318eae2-f07f-5a89-9f6f-7c47c4d86b1d", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "retraction-electrocardiogram" : { + "entries" : [ + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:6e5c97f9-3973-5275-a373-3bca6fb6f35c", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "retraction-heart-rate" : { + "entries" : [ + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:40c1b779-554a-5f23-8dde-da13be158027", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "retraction-heart-rate-native-identifier" : { + "entries" : [ + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:71fd3b0b-83cb-563d-9ab0-07f72410950b", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "sleep-analysis" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:b43d8154-effd-5996-b315-586eb5a39db3", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:zQKLnUUphK7g0a-sk45NT24jTx6o8QTbVhn8bRIo2XU", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:lKQTH6tKEWNaqQSgZvJePTwfGjO25t_9hpHjRVFFzCA" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:cea9def4-5bda-5d36-b41b-5bf3fbd5d6a0", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:gATgLvx899A7IxhUbWhlN8OUpTJj52a_KECMQj1skas", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:ce11774b-2935-5496-b436-476ffdf38238", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:31JVNmZIfD2Xpfq35NE2izl6k0ECexdC0alDLfc07Ws" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:56783614-946d-5967-b7c2-fc86470e730c", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:q4IDLT3D_h_mhcUMkD7HtvfDQL4DZSC54mYxjy-Q5n4", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:a16d704d-e1c7-5f2a-9566-0f5f2b29eefc", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "state-of-mind" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:f41c9c0c-4ade-5b30-9656-09ce3ce27cea", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:C31kj23cYeA6jPmlnmu7KniMnbewbD_yFCmczcnLOcU", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:10h795d6HZT3S4lfr1xQRkSSDDA8eC7FK8lrLZFyc84" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:99895048-f019-5e85-b351-90e3d78f8f5e", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:sdm-RvKwIE_gB3UWLsneUpPOXGhC9LgEKid_NCgO0bE" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:101d5877-ed8b-5129-ad8c-57a9562a47a5", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:tiEL4szorVEGCSEj-uxHK2XsnifbaJlUUKS2nGfCxF0", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:13546d51-ce74-5d3a-82e5-6a3ec9c287f2", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "step-count-period" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:0804d4b2-7569-5d86-a5ef-1da17a18c1ed", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:4dMwMpklfWvKOf615qiAmiIimIWIgvdjV2Wwwb8Sq2E", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:xoxfahmH97Ots54SkXpqBfHIQ-mROzWmEf83C-dPTik" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:eaa7e9c1-0c6c-5aad-9d5f-32b19a1b9417", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:4R7sis4gnIDMQKlyDYQ2E0EyGDLPh_QT6NCPVVtCuAw", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:4bc45344-330f-55e7-ba02-f4a87e38325d", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:VQfhWVUHYt0z7xXkA5RdGcwhHxTFVXMJMOExVf82Ru0" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:4f69efd2-67ad-53bd-8aea-0f809b71762d", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:GEB_CddWTYjrCywzQ_ZwqisfzqdSnZMJVI91TLt18SU", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:46e8aad6-e065-5339-a6c6-f70d26faaab3", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "sync-identity" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-writer-record-version" + ], + "fullUrl" : "urn:uuid:ecd979c9-a1e9-5edd-9297-4427ce7cad0f", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:4EmSopRc4c2piC9KH89pHBhpscDgWQNEMkApbHjjAss", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:azF0ncySV5bRvA76UbzfsmmFaHRAGNfWcAVougYu2wA", + "writer-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/writer-record/test/1|v0:test:1:vIfSIjXEDH2sYfmrl7Plzyh6_3t3FdXKG5O2EZe5vpQ" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:cd6d3a8d-da87-5612-ad8e-5b9b8bc3e083", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:R-HGqWARhWVYjX48QOw5kt_qeeHZLBKyzQ92CVzqkVY", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:0ecd8aec-0c4d-5980-9372-be968590aa04", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:KSh_1crRW1a7pld1ylhDhES7P7TG0VTo1gzyj37IMsw" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:576bda00-70ad-5e9e-91bf-9d1b4c70e27c", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:kHh6_2L6Ifqc1CeVvKx_sAk5YlSXNQUR47z9MAfx4UI", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:0147f49c-85e9-5f59-ac96-9aa59ab5a95a", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:fmH9C1ZPJvtfOrfpjdru2Qag-bhpbuknhG6nPeLFOC0" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:465dbaa1-25db-5cca-b00d-a481c25b1f47", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:9ecnWu7d62NEgUZI2ZDVAND_pemYjzWIDIC_7NSoKEg", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:067096fc-beae-5a55-8ed0-ebd16943d4a4", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "two-study-enrollments" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "http://hl7.org/fhir/StructureDefinition/workflow-researchStudy", + "http://hl7.org/fhir/StructureDefinition/workflow-researchStudy" + ], + "fullUrl" : "urn:uuid:fe81d51a-ee50-598d-9277-94eb6e72b2dc", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:EAfzgJ2XyqdxxpB1iP4fwZ76uvn04nSi6ulC-6pDCRQ", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:Pws2ERj3mLDY6x4GiBfTWfBLmWaZ9cv91TGd-D_bBA0" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:7b2c0ec4-d0b3-5cfc-a2de-4e0ea28ed384", + "identifiers" : [ + "-|https://grovealliance.org/fhir/testing/identifiers/researchstudy|study-a" + ], + "resourceType" : "ResearchStudy" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:c0794986-de9b-5f29-be1f-d6c199f9822e", + "identifiers" : [ + + ], + "resourceType" : "PlanDefinition" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:4f631875-e1cf-5bd6-8e73-b6d4d5cb495a", + "identifiers" : [ + "-|https://grovealliance.org/fhir/testing/identifiers/researchsubject|enrollment-study-a" + ], + "resourceType" : "ResearchSubject" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:807c5593-dee9-5419-8996-1dd9362ccf36", + "identifiers" : [ + "-|https://grovealliance.org/fhir/testing/identifiers/researchstudy|study-b" + ], + "resourceType" : "ResearchStudy" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:c3e91801-e451-5aff-80be-28cb606280f2", + "identifiers" : [ + + ], + "resourceType" : "PlanDefinition" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:0e290d26-099d-5ce1-a20a-0f3baed516d7", + "identifiers" : [ + "-|https://grovealliance.org/fhir/testing/identifiers/researchsubject|enrollment-study-b" + ], + "resourceType" : "ResearchSubject" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:281d53ee-64e5-5cf2-a11f-d0f564e84024", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:Nk8KPrH5Dn1BdMa9zp3Be-FuVfrFujF2V7Z15hhPf5E", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:4d8c8a3d-38bc-5cab-9083-ac8951f95ce7", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:5a15JwxquZ7nNljeGLJERTsbmE09kj22ZJiIRZuiALo" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:5fc579bd-75b8-5947-a611-1fc56e947a6f", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:a0MXEWJBc-SmkdL1zkFDeEI97rtGeGgCFFJafT_Nr0E", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:2a8208fd-d3b8-5a36-8e6c-fe64275ae3da", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:sCbUtg1XzO_e542E4iGvl-7azN_HrA-xeJY-_lKT4mU" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:e34dda89-a30e-5394-b8ee-b0595e1dd7c7", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:0eQT9MSgmDUzAt5YAOtzBtq0j7yF5fxtUi1dn7uOCSs", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:056345d7-1620-5265-8d21-48f208bb6912", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "udi-disclosure" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:e8f523b7-7621-51bc-989d-4f04a99ea342", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:KFrqQIWZ1vzA1E4nHWZK8scz5uBD45F7lgTTBvPopGk", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:OCn1ioiCza7pDKX0-wPk59s8vQP21_azMHwH1B7dp_8" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:bee8ea48-fb80-53cc-b38d-ddcc8d69c100", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:itFQYQtkBrdGnRBZsPkMkMRzUy1n0tu-HMDxJCixkwQ", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:d4d80f52-376f-59c3-b242-3dd7866b2615", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:_1KrMsSoa7w9ai_qWPtrne3RbZzKgGIxY-sFdW_OJZI" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:9f739129-65e9-5336-82d6-e43c24c8fe1b", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:3j4dl-rVT_GT7QkM0v5Dn8B8Rb5joZY7ly0-uFWow9o", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:590dd017-f9f1-5627-abdc-b1f47959e10e", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:dsehRkerbhq5Zpa3OMFFW-A4luy7TMC5YMDHAuSpjmQ" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:4f6c6282-7153-5005-8765-7a6ad1ac2428", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:Xco8n8XZVuOnolvaApgk2zQXo6uD_kN4mInjVU4YArw", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:72e479ff-2837-5a91-b3ca-206efadd6c57", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "workout-route" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:e2805cbe-fbd0-5906-a03c-9b2ab1409bc0", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:BXZhB-YbBLS8z00PfVyZ59S4HQZEaTrjemwVNwo0cEE", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:yqEjmAJYDXhs3IVPiRN7AyTHy5vj3W8s0hXYnY-mw7k", + "source-artifact|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1|v0:test:1:xQYRW8dFjjHC1ngz7sgpqn83gnGiw7wXcHAHwdynsIU" + ], + "resourceType" : "DocumentReference" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:67ee594f-5491-5c52-b199-eb7fb534436c", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:sopJ7r7cGsB8SNRwgrDDfVIxQdh4Yi0qsGv_-ewUKhw", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:81a02ecd-3890-5159-9e08-a92d1ff34063", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:keGqikaVp1KtP-VTXpXOgfrMY3JhLPacllBRGwnm0XA" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:7df29fa2-86f9-5ea8-a447-48cda6aae354", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:SBfJSawsIM7ABTa02UUwQX4uz0AfvVzCOluHfM5zcm0", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:18fba38a-2ee6-5140-80f2-d84f938266b4", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:s6mSUHde0SIpXeVJUkt29HnsauT6t_jVKVJw-KRRbK0" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:d21d9031-3216-5431-b57f-1b2afa147c46", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:cipjXhgIzQYdg8Q3ubLkiAipoA0S6MXNH1ydOvAju78", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:e961aa09-3fec-59b1-aab9-bb89371fb1d5", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "writer-blank-name-with-sync-identity" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-writer-record-version" + ], + "fullUrl" : "urn:uuid:4144d1e7-84d9-5f2b-a350-43608cf12bc7", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:SCRk4OXXsW9n_6oPuSi5S5a6zV81Hfny2vUBe8XTKt0", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:oei9-WTo3ZQOm6GXsGzyba5wfb8WXJ5EVOnfhLGpSCU", + "writer-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/writer-record/test/1|v0:test:1:vIfSIjXEDH2sYfmrl7Plzyh6_3t3FdXKG5O2EZe5vpQ" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:d956312f-4c23-50db-bc14-90e022e6d814", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:1XDSeObjR4wlja2kFFTrRkw6CjO32UYij_6RBdfOQbI", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:712f7b9b-943e-5588-b83b-1c5af97b4595", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:l4j_qZ5lQY0AmQsSnbkwKRVsnLJVZRnLdCwNqyQD1sA" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:5b5d1798-36d7-57b0-adb4-7a6a686629ca", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:W53r-MeL3d96IfkBs_sLWCZSjxsSTg37XRyYv-W1c44", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:80e3273c-3d80-5579-81d1-8e3a68996d21", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "writer-device-classification" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:1f546d61-156c-5bf0-80d4-95941c18de10", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:81UrlZhjo86nQB0UCszGzlJj2_LcPZVTZ_vC9OUQg3w", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:mFNEqBFhJaRsanQgDqFYN3IQM_vyL46YEvVV1uWOyw8" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:4d25df34-97c0-5441-a4e4-74e7de79ed10", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:KOTseOdrwvtSgbaOq5n_Uytq3S3yzISvXl3KuiKTqFc", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:695eb08b-1ea0-57d4-ba75-ef39692fb400", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:uTK8EAl121dqWmzpnRKwr2aIjkjsxLoOMGHTbDWuxe8" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:bdd116c3-04dd-5a9e-83c8-047e61d5efbc", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:YhDFNeOk54-8CpHFrvZQ58vSLNo5h_95dRECs3Iv05g", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:85f263ec-1ec6-58b5-887b-39cb81f5c339", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "writer-device-classification-without-recording-device" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:a86c10b2-c5d4-5e32-b20a-acf1f3d92c1b", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:KvwGqiFmJzXnyA32l_7VSMr9nQsORddnye-BgiPFpg0", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:YU4KNVWRqlp9mfF8E5Hpl-8cZ_v8_2XLdpuWi3I7vtg" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:f44a6514-7428-56e9-83e4-5c7ca029fe50", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:u9JvTYLnr4RT7IvVJoJgb76cGDJ-tfwIHsqeaQrBSBE" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:cc6451d0-7738-56a2-8df2-ab4cbdc8d4a6", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:-CyTyjpnePQUmb6-iYUJ-SQLUuAbAHLvYKiaBYtxpwg", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:31bc8e36-6ffe-5852-8126-3c045cfee93a", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "writer-foreign-application" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:a95889d1-0d54-516b-a6a9-a52b2bb1809f", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:AJz4f8aqK4pJ400P46nAgpmEFAIsR2Ysx4Q2mjQi_vo", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:pqCLAAGFRwSLHZRIbv_m2xU_YzPozJNYZbzOJe4paZI" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:0d697d80-71e1-5ba7-a59c-41877b725984", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:nRttzmH0-qkfZHsgJN7-w0HnszZ1o6dXmcMq1nirLxo", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:caa54c64-62e2-5f87-8a52-d461ce1e3265", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:R8jE6x3KkPw3WilQx6hegDC7fpB79JyXiIxA2ymK6t0" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:acec87ec-7a33-5a2e-8eb0-ba6e5c2da101", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:m8Bs7JWk3X2B-rQkZWnNXymQNjLxPLYM0j_6n_lhCG4", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:6dda8ddb-7e62-5220-b3be-1bda46fc5607", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:HA3QVfGVZkJ_eAJqmDQrBdEo-IavSPptqY5CoENRS-k" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:4b4f451f-5741-5465-9043-2565a381e500", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:MuXiWtyyfMnkHkYaZ_QJitDcMiXEFWtxTLwxVJcyYIQ", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:ed4de8c5-4bf5-5b2f-b948-5592de94fe86", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "writer-host-equals-converter-host" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:5599a011-2c26-59bb-a95c-40de982c2253", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:XmujUDtBGLEON9ZBNR4qUb1jXIXyx_J8pugN6uU1dvo", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:N1bsPg5Tpt9wBEW0ki5-9c1RxomFVnpucNSIymcJKFQ" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:9274a9b9-9a8b-5efc-af2d-304e81d0b30e", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:5GB6sZS_7W5Cgk-hDHObBDOz89ZpPK6EkdTRyahQK1o", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:43810cf8-8b6e-51f8-853b-664c10277672", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:w3TNXrnA2C6WOf_hwvPqROcYiOlEqWVdnCx1uQrEGcc" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:64a0a45c-e646-56fe-9e28-1b3c15a5ffeb", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:VmrsaBJYNbc7lxK9uRsEZEblajKYCiXbzGxNr90XCSY", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:a7bdd03c-01d1-5fa1-b065-2b5de07354d1", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:L-7r74u94S5VQCgUyZqLO8yPIUvCmcsNpTlwDPgkPpI", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:99b14254-dd46-5ebd-9052-73e667e3b3fc", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "writer-self-build-equals-revision" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:92465a78-7a3f-5726-b1d7-ee1018ef2f3e", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:4zOLoSjizi6BxZ461XZTg0Pr2wtZNXXm5c7SEudypKY", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:H7yUNVraO2BUJOM7_QY4twfGRocBMc5GOJLwytTksFU" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:f7ccb2bb-0bff-5730-bd5d-48e573cf3d89", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:XMmeXu7fRyMFrccTwdG0A5d_kJlKHeLCvXAr_Dws_WE", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:85fe11f2-bc5b-5b0f-abe3-5908657e664b", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:DWkZy6qN7lDWGCWE9njA9MDWwL9msiQziGy4cqGqM9s" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:94382637-b141-5b78-9506-125b8fa7cd3d", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:YwtHrVoKW5NfFHYkdhvQcEwiPXKdBnVv-aPn1f27dQY", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:854722cb-9bca-5eb9-af52-e2c354f18ef8", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:6mgRqjetEQP6M-CXoG17XC93bgw47v5zuZIurjpzziQ" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:d2533d04-4857-5137-9ef6-f3b3b3437eec", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:_ZBfe7GNZUCKegUJ1CKITz5rpxGaOeSHeXQQ6wurRE8", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:4031c305-e90a-56fa-87c3-286b4612aaa8", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "writer-self-older-build" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:45e6f1e8-2b41-5524-9794-097e83de95f2", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:EoaAO9mXym31Kh5UIGSlE-QHb5JwLtXWVZ9ufV2JhrQ", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:s4xlxhafc7RsPl_wQ-b96kSjFg2rXZuCIG3Hbw2Ew_o" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:1e4f60d6-f4a3-54ce-a5f9-235bf0c932f7", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:AuzFJ5dzw_Eea3WwhGBPaljG9MmXkooCE6UTFnJa6O0", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:f9b5d32c-fb8f-52dd-a414-35abda9d39db", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:FjfcSkiI7TKf0tpVXF45anjKiUaIuLOhHuMMXD27T6w" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:43352af1-c8d5-5a6d-9982-3192be805f9f", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:jMhsNHOkjaC9W-H2TWIJOJm1mTt6jf__smVZEM9xWhE", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:09c85600-150d-54d4-91d1-fdf5ca024fe6", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:Ab2HWd0MFBIc2-14EWGLAoWaIoGf55n-NPD_X3JdvNQ" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:98fa6785-6ecf-5477-81e8-43671d56b65c", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:sCSyThEwHrA-QNutyWoT8IvqvObAfx9iVgwMMjwgBlw", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:2cf28482-aa74-5f3e-9642-94909fbf9b82", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "writer-self-token-identical" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:6a599798-b1c3-5d65-bd14-8afd4d896374", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:UtyKmuNmZRtWC6Cb1iDLm9WSCg6brTP-ItN7sd1HhBE", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:vdd9BSjfFviTjyD8wkjFrlxpgvGd0nHijXDFBU4aEVI" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:f98c822b-f8b0-563c-a61d-16342d6d3e43", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:YQJIbbB8nuB0-RPnkaOOBSVaBuHjGSfhNNc4uwOODSc", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:417e9464-bb22-56ae-8bc4-58910aed36ce", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:duxmSr3Uxe-v-wJgeIcbhR64QQ7n3jy0TUBxvljFuaE" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:9f7774ef-99d1-57a1-8d3f-3d62a9055a0c", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:ETsCwd__V6NpQJf6VOxp0GvIf0JmozLFJ8URnCefuk8", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:4153f2f4-6bcb-5340-b209-f375de0c4a76", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "writer-without-version" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:e2dff379-9ae2-59e9-8ef6-57d88010ca64", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:pu9X9aITPkaZSwzXq0rNXketNBHLqnK_XJaLomKFdWs", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:71A8Gf5aQhQ_33O72ULGDB1iiEJi-ds1MChFYa6UtZE" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:673eb625-bb2a-5a9f-8be4-671921b101a8", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:45Uc_1_gwHsuABUimsyG1CL6Q_MEbWP1FAubfEtm6j8", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:bbba67f6-f6eb-5258-9f0b-9b89e14e786b", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:BtKDCQ-8uHZTri3NWIuleHdsbXZY6cyoialzqVtyubM" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:1fa02907-e6d9-58c2-9f33-a839357070ba", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:xrE6K8oKqbR1QnI3GZOJVDEyFiwiWhMkrQDLlbVFyu0", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:70151851-1494-57d5-a18e-9c62a5f04d94", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:3ntQLUR90EZUNsD1WNW60LY9c_USs_Z3DD47ED6vTZk" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:1eef1284-4494-52d0-b506-99f73e87783a", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:bVGe5u0L2gfNRE-aE7WuRImncvimhcHXi6DoTHn9-CA", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:e9e34d14-0317-5207-81ad-9abae89e4c8b", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + } +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/repository-ids-on-every-node.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/repository-ids-on-every-node.json new file mode 100644 index 000000000..edefa7e75 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/repository-ids-on-every-node.json @@ -0,0 +1,614 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:dFzIvPfelFY7OsDcfM18IY5G1nJgn02BNIHXScSWKsQ" + } + } + ], + "fullUrl" : "urn:uuid:bedd22e2-64c2-52eb-ad12-4fcd8b2f7116", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "device" : { + "reference" : "urn:uuid:8068aec8-be51-54d9-af86-bda3b55b2da9" + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + } + ], + "id" : "output-46", + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:QzF2mgRu5BLZ1u7h-O0-xttOmmOYiqgiZWnPoFh6aSo" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:dFzIvPfelFY7OsDcfM18IY5G1nJgn02BNIHXScSWKsQ" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:eB8Gf-LhSAaBL_oxV6y1Zodqv3uXKnvm67j60gXtEVg" + } + } + ], + "fullUrl" : "urn:uuid:8068aec8-be51-54d9-af86-bda3b55b2da9", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "id" : "recorder-46", + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:eB8Gf-LhSAaBL_oxV6y1Zodqv3uXKnvm67j60gXtEVg" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:uYtmRqrnSdKKb0_BQdY5Bai87GbCUpRwjurAtvoOA-8" + } + } + ], + "fullUrl" : "urn:uuid:3870e66b-7993-5249-b08d-a8ee4ab511e1", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "id" : "host-46", + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:uYtmRqrnSdKKb0_BQdY5Bai87GbCUpRwjurAtvoOA-8" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:N0D78V87eBkedJrHAL-1npBxK_OQ7ycRrVYu0-FcfMM" + } + } + ], + "fullUrl" : "urn:uuid:2d1d232a-dce0-5234-9f70-e6f1f57a06d2", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "id" : "app-46", + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:N0D78V87eBkedJrHAL-1npBxK_OQ7ycRrVYu0-FcfMM" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:3870e66b-7993-5249-b08d-a8ee4ab511e1" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:dG1NzkNlb5umEYXyrGnJZ9ModYp454veeMqiqWJOAPc" + } + } + ], + "fullUrl" : "urn:uuid:6835b79a-e720-5d06-8df2-376fc5675c58", + "resource" : { + "id" : "writer-host-46", + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:dG1NzkNlb5umEYXyrGnJZ9ModYp454veeMqiqWJOAPc" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "iPhone17,1", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "26.1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:s_Cee-Bm1PdPanXpAhVVnuPXTAgty-n1BHE5QPmtoVQ" + } + } + ], + "fullUrl" : "urn:uuid:676da85f-7976-593f-8308-df804c106a16", + "resource" : { + "deviceName" : [ + { + "name" : "Example Writer", + "type" : "user-friendly-name" + } + ], + "id" : "writer-46", + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:s_Cee-Bm1PdPanXpAhVVnuPXTAgty-n1BHE5QPmtoVQ" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.example.writer" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:6835b79a-e720-5d06-8df2-376fc5675c58" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "42" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:VDrJqTfGCscqHHhEoKR1bTz3HIqEfr1HPkP0w_VfVXk" + } + } + ], + "fullUrl" : "urn:uuid:f9387192-08d6-56d5-929b-57821c1a17b0", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:2d1d232a-dce0-5234-9f70-e6f1f57a06d2" + } + } + ], + "entity" : [ + { + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "author", + "display" : "Author", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:676da85f-7976-593f-8308-df804c106a16" + } + } + ], + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:QzF2mgRu5BLZ1u7h-O0-xttOmmOYiqgiZWnPoFh6aSo" + } + } + } + ], + "id" : "provenance-46", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:bedd22e2-64c2-52eb-ad12-4fcd8b2f7116" + } + ] + } + } + ], + "id" : "bundle-46", + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:46" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/retraction-blood-pressure.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/retraction-blood-pressure.json new file mode 100644 index 000000000..7f2f510b8 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/retraction-blood-pressure.json @@ -0,0 +1,135 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:retraction-provenance:0:fAw25bSUZ6W9S0SduSC6qzLnbODg3LhoxM45R0OxSGM" + } + } + ], + "fullUrl" : "urn:uuid:1318eae2-f07f-5a89-9f6f-7c47c4d86b1d", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "source-record-retracted", + "display" : "Source record retracted", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-lifecycle-event" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:biX_jRwJLPSA6RfvanSZ_z7f5KtOol1_U-lvZRzBJl4" + }, + "type" : "Device" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:MgVgKdjHDGPoWKHHny4JL3G7rU858AdEnejU3PTdKQQ" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-retraction-provenance" + ] + }, + "occurredPeriod" : { + "end" : "2026-08-17T23:30:00Z" + }, + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-retraction-target-role", + "valueCode" : "primary-output" + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Vc6xFr7v7_L2zbSyvNJd0CMHcNKblhZQ6y1Tx57PpuA" + }, + "type" : "Observation" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:83" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-retraction-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/retraction-electrocardiogram.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/retraction-electrocardiogram.json new file mode 100644 index 000000000..d0dc4db38 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/retraction-electrocardiogram.json @@ -0,0 +1,154 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:retraction-provenance:0:-49nDsqVBV_aX4zKfxm-w2mWtnO7U0bFgtdDMXMLcqY" + } + } + ], + "fullUrl" : "urn:uuid:6e5c97f9-3973-5275-a373-3bca6fb6f35c", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "source-record-retracted", + "display" : "Source record retracted", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-lifecycle-event" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Nq9UvpKLOdLXoIb1BbMjMZDOOMZEweQBBD3ku0LJC1Y" + }, + "type" : "Device" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Rafsg0P5eS2riuHijF6VVUqQ7_eYlQMTazZiVLIGCoE" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-retraction-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-retraction-target-role", + "valueCode" : "primary-output" + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Xk3J0csCpaST52SJf5WCk1IjC48bIt1M-LX_XdRHSNA" + }, + "type" : "Observation" + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-retraction-target-role", + "valueCode" : "child-output" + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Mz4QMokK3VR146NKuEPbn6xQPEouq6s_-JifM3KVh4Y" + }, + "type" : "Observation" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:82" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-retraction-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/retraction-heart-rate-native-identifier.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/retraction-heart-rate-native-identifier.json new file mode 100644 index 000000000..0970ec3c0 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/retraction-heart-rate-native-identifier.json @@ -0,0 +1,143 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:retraction-provenance:0:QxZfZyjPqYGIqMIvziC8psng-HmyQap2OFp6lhRITCw" + } + } + ], + "fullUrl" : "urn:uuid:71fd3b0b-83cb-563d-9ab0-07f72410950b", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "source-record-retracted", + "display" : "Source record retracted", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-lifecycle-event" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:UmtaMP4UDBwS97ZTY6TI-q1G_00AlrZR9hl_9_vl74A" + }, + "type" : "Device" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:w90mrxwrL9dEEYfQDJw2nkidLAlQOtQ3IVWEoVn47cM" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-retraction-provenance" + ] + }, + "occurredPeriod" : { + "end" : "2026-08-17T23:30:00Z", + "start" : "2026-08-17T22:30:00Z" + }, + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-retraction-target-role", + "valueCode" : "primary-output" + }, + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-retraction-target-native-identifier", + "valueIdentifier" : { + "system" : "https://study.example.org/fhir/NamingSystem/healthkit-store", + "value" : "3a7e5c10-0000-4000-8000-000000000051" + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:FVwIEHab84qe9SNBUTQAokZqjdM8wJocCCKIVYAXpb0" + }, + "type" : "Observation" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:81" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-retraction-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/retraction-heart-rate.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/retraction-heart-rate.json new file mode 100644 index 000000000..a0fdf319e --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/retraction-heart-rate.json @@ -0,0 +1,133 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:retraction-provenance:0:qmMS6TAzQat50ewpsIXygInh9zh18KDEGFKNWp_04MU" + } + } + ], + "fullUrl" : "urn:uuid:40c1b779-554a-5f23-8dde-da13be158027", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "source-record-retracted", + "display" : "Source record retracted", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-lifecycle-event" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Aq-ML54fQv3OI6KtuctHPlDFKoNXZj5QK3twyhvHOYw" + }, + "type" : "Device" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:SWK6N4k5IwFB3RJH3I9PkXhFNrT4cRYXUosy8MFvzn0" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-retraction-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-retraction-target-role", + "valueCode" : "primary-output" + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:U5OjoNfckdk5OZa3yGFsGJ1vzD0HXwUbdq3kCC41_b4" + }, + "type" : "Observation" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:80" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-retraction-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/sleep-analysis.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/sleep-analysis.json new file mode 100644 index 000000000..99672cee9 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/sleep-analysis.json @@ -0,0 +1,473 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:lKQTH6tKEWNaqQSgZvJePTwfGjO25t_9hpHjRVFFzCA" + } + } + ], + "fullUrl" : "urn:uuid:b43d8154-effd-5996-b315-586eb5a39db3", + "resource" : { + "category" : [ + { + "coding" : [ + { + "code" : "activity", + "display" : "Activity", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "sleep-stage", + "display" : "Sleep stage", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement" + } + ] + }, + "device" : { + "reference" : "urn:uuid:cea9def4-5bda-5d36-b41b-5bf3fbd5d6a0" + }, + "effectivePeriod" : { + "_end" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "_start" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "end" : "2026-08-17T16:30:00-07:00", + "start" : "2026-08-17T15:30:00-07:00" + }, + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKCategoryTypeIdentifierSleepAnalysis" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:zQKLnUUphK7g0a-sk45NT24jTx6o8QTbVhn8bRIo2XU" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:lKQTH6tKEWNaqQSgZvJePTwfGjO25t_9hpHjRVFFzCA" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-sleep-stage", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueCodeableConcept" : { + "coding" : [ + { + "code" : "light", + "display" : "Light sleep", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-sleep-stage" + }, + { + "code" : "asleepCore", + "display" : "Asleep, core", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-sleep-analysis" + } + ] + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:gATgLvx899A7IxhUbWhlN8OUpTJj52a_KECMQj1skas" + } + } + ], + "fullUrl" : "urn:uuid:cea9def4-5bda-5d36-b41b-5bf3fbd5d6a0", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:gATgLvx899A7IxhUbWhlN8OUpTJj52a_KECMQj1skas" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:31JVNmZIfD2Xpfq35NE2izl6k0ECexdC0alDLfc07Ws" + } + } + ], + "fullUrl" : "urn:uuid:ce11774b-2935-5496-b436-476ffdf38238", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:31JVNmZIfD2Xpfq35NE2izl6k0ECexdC0alDLfc07Ws" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:q4IDLT3D_h_mhcUMkD7HtvfDQL4DZSC54mYxjy-Q5n4" + } + } + ], + "fullUrl" : "urn:uuid:56783614-946d-5967-b7c2-fc86470e730c", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:q4IDLT3D_h_mhcUMkD7HtvfDQL4DZSC54mYxjy-Q5n4" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:ce11774b-2935-5496-b436-476ffdf38238" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:8zpGrPPuKdttlizZdfeyikNKQJcQavPJ0fN4uVeHnwk" + } + } + ], + "fullUrl" : "urn:uuid:a16d704d-e1c7-5f2a-9566-0f5f2b29eefc", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:56783614-946d-5967-b7c2-fc86470e730c" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:zQKLnUUphK7g0a-sk45NT24jTx6o8QTbVhn8bRIo2XU" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:b43d8154-effd-5996-b315-586eb5a39db3" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:10" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/state-of-mind.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/state-of-mind.json new file mode 100644 index 000000000..1372ddc3e --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/state-of-mind.json @@ -0,0 +1,423 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:10h795d6HZT3S4lfr1xQRkSSDDA8eC7FK8lrLZFyc84" + } + } + ], + "fullUrl" : "urn:uuid:f41c9c0c-4ade-5b30-9656-09ce3ce27cea", + "resource" : { + "code" : { + "coding" : [ + { + "code" : "state-of-mind", + "display" : "State of mind", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement" + } + ] + }, + "component" : [ + { + "code" : { + "coding" : [ + { + "code" : "kind", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement" + } + ] + }, + "valueCodeableConcept" : { + "coding" : [ + { + "code" : "momentary-emotion", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind" + } + ] + } + }, + { + "code" : { + "coding" : [ + { + "code" : "valence-classification", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement" + } + ] + }, + "valueCodeableConcept" : { + "coding" : [ + { + "code" : "pleasant", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification" + } + ] + } + }, + { + "code" : { + "coding" : [ + { + "code" : "state-of-mind-label", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement" + } + ] + }, + "valueCodeableConcept" : { + "coding" : [ + { + "code" : "happy", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label" + } + ] + } + }, + { + "code" : { + "coding" : [ + { + "code" : "state-of-mind-association", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement" + } + ] + }, + "valueCodeableConcept" : { + "coding" : [ + { + "code" : "work", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association" + } + ] + } + } + ], + "effectivePeriod" : { + "_end" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "_start" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "end" : "2026-08-17T15:30:00-07:00", + "start" : "2026-08-17T15:30:00-07:00" + }, + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKDataTypeStateOfMind" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:C31kj23cYeA6jPmlnmu7KniMnbewbD_yFCmczcnLOcU" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:10h795d6HZT3S4lfr1xQRkSSDDA8eC7FK8lrLZFyc84" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "1", + "system" : "http://unitsofmeasure.org", + "unit" : "valence", + "value" : 0.5 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:sdm-RvKwIE_gB3UWLsneUpPOXGhC9LgEKid_NCgO0bE" + } + } + ], + "fullUrl" : "urn:uuid:99895048-f019-5e85-b351-90e3d78f8f5e", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:sdm-RvKwIE_gB3UWLsneUpPOXGhC9LgEKid_NCgO0bE" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:tiEL4szorVEGCSEj-uxHK2XsnifbaJlUUKS2nGfCxF0" + } + } + ], + "fullUrl" : "urn:uuid:101d5877-ed8b-5129-ad8c-57a9562a47a5", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:tiEL4szorVEGCSEj-uxHK2XsnifbaJlUUKS2nGfCxF0" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:99895048-f019-5e85-b351-90e3d78f8f5e" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:0aFhOXFAv5IQIcjhnfDEBmwVf5onBY3JqRKSc-8FffU" + } + } + ], + "fullUrl" : "urn:uuid:13546d51-ce74-5d3a-82e5-6a3ec9c287f2", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:101d5877-ed8b-5129-ad8c-57a9562a47a5" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:C31kj23cYeA6jPmlnmu7KniMnbewbD_yFCmczcnLOcU" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:f41c9c0c-4ade-5b30-9656-09ce3ce27cea" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:11" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/step-count-period.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/step-count-period.json new file mode 100644 index 000000000..1aec59d1a --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/step-count-period.json @@ -0,0 +1,465 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:xoxfahmH97Ots54SkXpqBfHIQ-mROzWmEf83C-dPTik" + } + } + ], + "fullUrl" : "urn:uuid:0804d4b2-7569-5d86-a5ef-1da17a18c1ed", + "resource" : { + "category" : [ + { + "coding" : [ + { + "code" : "activity", + "display" : "Activity", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "step-count-total", + "display" : "Step count total", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement" + } + ] + }, + "device" : { + "reference" : "urn:uuid:eaa7e9c1-0c6c-5aad-9d5f-32b19a1b9417" + }, + "effectivePeriod" : { + "_end" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "_start" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "end" : "2026-08-17T15:31:00-07:00", + "start" : "2026-08-17T15:30:00-07:00" + }, + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierStepCount" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:4dMwMpklfWvKOf615qiAmiIimIWIgvdjV2Wwwb8Sq2E" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:xoxfahmH97Ots54SkXpqBfHIQ-mROzWmEf83C-dPTik" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "{steps}", + "system" : "http://unitsofmeasure.org", + "unit" : "steps", + "value" : 120 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:4R7sis4gnIDMQKlyDYQ2E0EyGDLPh_QT6NCPVVtCuAw" + } + } + ], + "fullUrl" : "urn:uuid:eaa7e9c1-0c6c-5aad-9d5f-32b19a1b9417", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:4R7sis4gnIDMQKlyDYQ2E0EyGDLPh_QT6NCPVVtCuAw" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:VQfhWVUHYt0z7xXkA5RdGcwhHxTFVXMJMOExVf82Ru0" + } + } + ], + "fullUrl" : "urn:uuid:4bc45344-330f-55e7-ba02-f4a87e38325d", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:VQfhWVUHYt0z7xXkA5RdGcwhHxTFVXMJMOExVf82Ru0" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:GEB_CddWTYjrCywzQ_ZwqisfzqdSnZMJVI91TLt18SU" + } + } + ], + "fullUrl" : "urn:uuid:4f69efd2-67ad-53bd-8aea-0f809b71762d", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:GEB_CddWTYjrCywzQ_ZwqisfzqdSnZMJVI91TLt18SU" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:4bc45344-330f-55e7-ba02-f4a87e38325d" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:n1dW5SrupFIhWmJc9Y9wTVAftxQuf-6tQLv0zci1h1k" + } + } + ], + "fullUrl" : "urn:uuid:46e8aad6-e065-5339-a6c6-f70d26faaab3", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:4f69efd2-67ad-53bd-8aea-0f809b71762d" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:4dMwMpklfWvKOf615qiAmiIimIWIgvdjV2Wwwb8Sq2E" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:0804d4b2-7569-5d86-a5ef-1da17a18c1ed" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:8" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/sync-identity.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/sync-identity.json new file mode 100644 index 000000000..4d171c136 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/sync-identity.json @@ -0,0 +1,622 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:azF0ncySV5bRvA76UbzfsmmFaHRAGNfWcAVougYu2wA" + } + } + ], + "fullUrl" : "urn:uuid:ecd979c9-a1e9-5edd-9297-4427ce7cad0f", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "device" : { + "reference" : "urn:uuid:cd6d3a8d-da87-5612-ad8e-5b9b8bc3e083" + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + }, + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-writer-record-version", + "valueString" : "3" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:4EmSopRc4c2piC9KH89pHBhpscDgWQNEMkApbHjjAss" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:azF0ncySV5bRvA76UbzfsmmFaHRAGNfWcAVougYu2wA" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/writer-record/test/1", + "type" : { + "coding" : [ + { + "code" : "writer-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:vIfSIjXEDH2sYfmrl7Plzyh6_3t3FdXKG5O2EZe5vpQ" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:R-HGqWARhWVYjX48QOw5kt_qeeHZLBKyzQ92CVzqkVY" + } + } + ], + "fullUrl" : "urn:uuid:cd6d3a8d-da87-5612-ad8e-5b9b8bc3e083", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:R-HGqWARhWVYjX48QOw5kt_qeeHZLBKyzQ92CVzqkVY" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:KSh_1crRW1a7pld1ylhDhES7P7TG0VTo1gzyj37IMsw" + } + } + ], + "fullUrl" : "urn:uuid:0ecd8aec-0c4d-5980-9372-be968590aa04", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:KSh_1crRW1a7pld1ylhDhES7P7TG0VTo1gzyj37IMsw" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:kHh6_2L6Ifqc1CeVvKx_sAk5YlSXNQUR47z9MAfx4UI" + } + } + ], + "fullUrl" : "urn:uuid:576bda00-70ad-5e9e-91bf-9d1b4c70e27c", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:kHh6_2L6Ifqc1CeVvKx_sAk5YlSXNQUR47z9MAfx4UI" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:0ecd8aec-0c4d-5980-9372-be968590aa04" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:fmH9C1ZPJvtfOrfpjdru2Qag-bhpbuknhG6nPeLFOC0" + } + } + ], + "fullUrl" : "urn:uuid:0147f49c-85e9-5f59-ac96-9aa59ab5a95a", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:fmH9C1ZPJvtfOrfpjdru2Qag-bhpbuknhG6nPeLFOC0" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "iPhone17,1", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "26.1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:9ecnWu7d62NEgUZI2ZDVAND_pemYjzWIDIC_7NSoKEg" + } + } + ], + "fullUrl" : "urn:uuid:465dbaa1-25db-5cca-b00d-a481c25b1f47", + "resource" : { + "deviceName" : [ + { + "name" : "Example Writer", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:9ecnWu7d62NEgUZI2ZDVAND_pemYjzWIDIC_7NSoKEg" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.example.writer" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:0147f49c-85e9-5f59-ac96-9aa59ab5a95a" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "42" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:0PO4RS4d1Di3R7NLQshyOuWFG8qUUJ3afTt3yR7sDeI" + } + } + ], + "fullUrl" : "urn:uuid:067096fc-beae-5a55-8ed0-ebd16943d4a4", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:576bda00-70ad-5e9e-91bf-9d1b4c70e27c" + } + } + ], + "entity" : [ + { + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "author", + "display" : "Author", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:465dbaa1-25db-5cca-b00d-a481c25b1f47" + } + } + ], + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:4EmSopRc4c2piC9KH89pHBhpscDgWQNEMkApbHjjAss" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:ecd979c9-a1e9-5edd-9297-4427ce7cad0f" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:29" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/two-study-enrollments.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/two-study-enrollments.json new file mode 100644 index 000000000..72b50957d --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/two-study-enrollments.json @@ -0,0 +1,822 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Pws2ERj3mLDY6x4GiBfTWfBLmWaZ9cv91TGd-D_bBA0" + } + } + ], + "fullUrl" : "urn:uuid:fe81d51a-ee50-598d-9277-94eb6e72b2dc", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "device" : { + "reference" : "urn:uuid:281d53ee-64e5-5cf2-a11f-d0f564e84024" + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + }, + { + "url" : "http://hl7.org/fhir/StructureDefinition/workflow-researchStudy", + "valueReference" : { + "reference" : "urn:uuid:7b2c0ec4-d0b3-5cfc-a2de-4e0ea28ed384", + "type" : "ResearchStudy" + } + }, + { + "url" : "http://hl7.org/fhir/StructureDefinition/workflow-researchStudy", + "valueReference" : { + "reference" : "urn:uuid:807c5593-dee9-5419-8996-1dd9362ccf36", + "type" : "ResearchStudy" + } + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:EAfzgJ2XyqdxxpB1iP4fwZ76uvn04nSi6ulC-6pDCRQ" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Pws2ERj3mLDY6x4GiBfTWfBLmWaZ9cv91TGd-D_bBA0" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:research-study:0:985OIoL_z-xafD1Q8EwdIcDyt-BCgNDWx8lxF9BKqKE" + } + } + ], + "fullUrl" : "urn:uuid:7b2c0ec4-d0b3-5cfc-a2de-4e0ea28ed384", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/researchstudy", + "value" : "study-a" + } + ], + "protocol" : [ + { + "reference" : "urn:uuid:c0794986-de9b-5f29-be1f-d6c199f9822e" + } + ], + "resourceType" : "ResearchStudy", + "status" : "active" + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:plan-definition:0:M4W--wthtfyVMZUVUvnS716YuHSA5pahJvXrtp9DjIo" + } + } + ], + "fullUrl" : "urn:uuid:c0794986-de9b-5f29-be1f-d6c199f9822e", + "resource" : { + "resourceType" : "PlanDefinition", + "status" : "active", + "url" : "https://study.example.org/PlanDefinition/study-a", + "version" : "1" + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:research-subject:0:zRrlt7F0AjUMsfJOBkt5eq3XRhzhAK5k-4qI1BSgWAc" + } + } + ], + "fullUrl" : "urn:uuid:4f631875-e1cf-5bd6-8e73-b6d4d5cb495a", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/researchsubject", + "value" : "enrollment-study-a" + } + ], + "individual" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "resourceType" : "ResearchSubject", + "status" : "on-study", + "study" : { + "reference" : "urn:uuid:7b2c0ec4-d0b3-5cfc-a2de-4e0ea28ed384" + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:research-study:1:OJUjZ1w7tAgprti-zwD3hgWerDMoQfDiR4O6GL09IjU" + } + } + ], + "fullUrl" : "urn:uuid:807c5593-dee9-5419-8996-1dd9362ccf36", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/researchstudy", + "value" : "study-b" + } + ], + "protocol" : [ + { + "reference" : "urn:uuid:c3e91801-e451-5aff-80be-28cb606280f2" + } + ], + "resourceType" : "ResearchStudy", + "status" : "active" + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:plan-definition:1:R1InBGwJq9mONDU2Vd6Dhh1UueAxStcG-cu9L_H3004" + } + } + ], + "fullUrl" : "urn:uuid:c3e91801-e451-5aff-80be-28cb606280f2", + "resource" : { + "resourceType" : "PlanDefinition", + "status" : "active", + "url" : "https://study.example.org/PlanDefinition/study-b", + "version" : "1" + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:research-subject:1:tpKGEclvuoBtoGeVJ91YbX71XlPbs09l2pPQGOmMPoY" + } + } + ], + "fullUrl" : "urn:uuid:0e290d26-099d-5ce1-a20a-0f3baed516d7", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/researchsubject", + "value" : "enrollment-study-b" + } + ], + "individual" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "resourceType" : "ResearchSubject", + "status" : "on-study", + "study" : { + "reference" : "urn:uuid:807c5593-dee9-5419-8996-1dd9362ccf36" + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Nk8KPrH5Dn1BdMa9zp3Be-FuVfrFujF2V7Z15hhPf5E" + } + } + ], + "fullUrl" : "urn:uuid:281d53ee-64e5-5cf2-a11f-d0f564e84024", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Nk8KPrH5Dn1BdMa9zp3Be-FuVfrFujF2V7Z15hhPf5E" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:5a15JwxquZ7nNljeGLJERTsbmE09kj22ZJiIRZuiALo" + } + } + ], + "fullUrl" : "urn:uuid:4d8c8a3d-38bc-5cab-9083-ac8951f95ce7", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:5a15JwxquZ7nNljeGLJERTsbmE09kj22ZJiIRZuiALo" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:a0MXEWJBc-SmkdL1zkFDeEI97rtGeGgCFFJafT_Nr0E" + } + } + ], + "fullUrl" : "urn:uuid:5fc579bd-75b8-5947-a611-1fc56e947a6f", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:a0MXEWJBc-SmkdL1zkFDeEI97rtGeGgCFFJafT_Nr0E" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:4d8c8a3d-38bc-5cab-9083-ac8951f95ce7" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:sCbUtg1XzO_e542E4iGvl-7azN_HrA-xeJY-_lKT4mU" + } + } + ], + "fullUrl" : "urn:uuid:2a8208fd-d3b8-5a36-8e6c-fe64275ae3da", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:sCbUtg1XzO_e542E4iGvl-7azN_HrA-xeJY-_lKT4mU" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "iPhone17,1", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "26.1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:0eQT9MSgmDUzAt5YAOtzBtq0j7yF5fxtUi1dn7uOCSs" + } + } + ], + "fullUrl" : "urn:uuid:e34dda89-a30e-5394-b8ee-b0595e1dd7c7", + "resource" : { + "deviceName" : [ + { + "name" : "Example Writer", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:0eQT9MSgmDUzAt5YAOtzBtq0j7yF5fxtUi1dn7uOCSs" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.example.writer" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:2a8208fd-d3b8-5a36-8e6c-fe64275ae3da" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "42" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:-gcbpgHs0N2oqt-W-jWhlvCoOOHVT-PUSQo5GakotHs" + } + } + ], + "fullUrl" : "urn:uuid:056345d7-1620-5265-8d21-48f208bb6912", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:5fc579bd-75b8-5947-a611-1fc56e947a6f" + } + } + ], + "entity" : [ + { + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "author", + "display" : "Author", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:e34dda89-a30e-5394-b8ee-b0595e1dd7c7" + } + } + ], + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:EAfzgJ2XyqdxxpB1iP4fwZ76uvn04nSi6ulC-6pDCRQ" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:fe81d51a-ee50-598d-9277-94eb6e72b2dc" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:45" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/udi-disclosure.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/udi-disclosure.json new file mode 100644 index 000000000..15c50ec46 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/udi-disclosure.json @@ -0,0 +1,611 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:OCn1ioiCza7pDKX0-wPk59s8vQP21_azMHwH1B7dp_8" + } + } + ], + "fullUrl" : "urn:uuid:e8f523b7-7621-51bc-989d-4f04a99ea342", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "device" : { + "reference" : "urn:uuid:bee8ea48-fb80-53cc-b38d-ddcc8d69c100" + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:KFrqQIWZ1vzA1E4nHWZK8scz5uBD45F7lgTTBvPopGk" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:OCn1ioiCza7pDKX0-wPk59s8vQP21_azMHwH1B7dp_8" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:itFQYQtkBrdGnRBZsPkMkMRzUy1n0tu-HMDxJCixkwQ" + } + } + ], + "fullUrl" : "urn:uuid:bee8ea48-fb80-53cc-b38d-ddcc8d69c100", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:itFQYQtkBrdGnRBZsPkMkMRzUy1n0tu-HMDxJCixkwQ" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "udiCarrier" : [ + { + "deviceIdentifier" : "(01)00844588003288" + } + ], + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:_1KrMsSoa7w9ai_qWPtrne3RbZzKgGIxY-sFdW_OJZI" + } + } + ], + "fullUrl" : "urn:uuid:d4d80f52-376f-59c3-b242-3dd7866b2615", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:_1KrMsSoa7w9ai_qWPtrne3RbZzKgGIxY-sFdW_OJZI" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:3j4dl-rVT_GT7QkM0v5Dn8B8Rb5joZY7ly0-uFWow9o" + } + } + ], + "fullUrl" : "urn:uuid:9f739129-65e9-5336-82d6-e43c24c8fe1b", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:3j4dl-rVT_GT7QkM0v5Dn8B8Rb5joZY7ly0-uFWow9o" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:d4d80f52-376f-59c3-b242-3dd7866b2615" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:dsehRkerbhq5Zpa3OMFFW-A4luy7TMC5YMDHAuSpjmQ" + } + } + ], + "fullUrl" : "urn:uuid:590dd017-f9f1-5627-abdc-b1f47959e10e", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:dsehRkerbhq5Zpa3OMFFW-A4luy7TMC5YMDHAuSpjmQ" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "iPhone17,1", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "26.1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Xco8n8XZVuOnolvaApgk2zQXo6uD_kN4mInjVU4YArw" + } + } + ], + "fullUrl" : "urn:uuid:4f6c6282-7153-5005-8765-7a6ad1ac2428", + "resource" : { + "deviceName" : [ + { + "name" : "Example Writer", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Xco8n8XZVuOnolvaApgk2zQXo6uD_kN4mInjVU4YArw" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.example.writer" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:590dd017-f9f1-5627-abdc-b1f47959e10e" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "42" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:SZqBVyiOsv6BUzVom9eayXjGCoQHLVbf25JCj3lWANc" + } + } + ], + "fullUrl" : "urn:uuid:72e479ff-2837-5a91-b3ca-206efadd6c57", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:9f739129-65e9-5336-82d6-e43c24c8fe1b" + } + } + ], + "entity" : [ + { + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "author", + "display" : "Author", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:4f6c6282-7153-5005-8765-7a6ad1ac2428" + } + } + ], + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:KFrqQIWZ1vzA1E4nHWZK8scz5uBD45F7lgTTBvPopGk" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:e8f523b7-7621-51bc-989d-4f04a99ea342" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:41" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/workout-route.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/workout-route.json new file mode 100644 index 000000000..35bf63aca --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/workout-route.json @@ -0,0 +1,612 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:yqEjmAJYDXhs3IVPiRN7AyTHy5vj3W8s0hXYnY-mw7k" + } + } + ], + "fullUrl" : "urn:uuid:e2805cbe-fbd0-5906-a03c-9b2ab1409bc0", + "resource" : { + "author" : [ + { + "reference" : "urn:uuid:67ee594f-5491-5c52-b199-eb7fb534436c" + }, + { + "reference" : "urn:uuid:7df29fa2-86f9-5ea8-a447-48cda6aae354" + } + ], + "content" : [ + { + "attachment" : { + "contentType" : "text/csv", + "data" : "dGltZXN0YW1wLGxhdGl0dWRlLGxvbmdpdHVkZSxhbHRpdHVkZSxob3Jpem9udGFsQWNjdXJhY3ksdmVydGljYWxBY2N1cmFjeSxzcGVlZCxzcGVlZEFjY3VyYWN5LGNvdXJzZSxjb3Vyc2VBY2N1cmFjeQoxNzg3MDA1ODAwLDM3LjQyNzUsLTEyMi4xNjk3LDMwLjUsNSwzLDIuMjUsMC41LDkxLjUsMTAKMTc4NzAwNTgwMSwzNy40Mjc2LC0xMjIuMTY5OCwwLDY1LCwsLCwK", + "hash" : "LGXyPSpUR5Ja3QMX1pYAf72h4mY=", + "size" : 210, + "title" : "Workout route locations" + }, + "format" : { + "code" : "location-track-samples", + "system" : "https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format" + } + } + ], + "date" : "2026-08-17T23:30:00Z", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKWorkoutRouteTypeIdentifier" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:BXZhB-YbBLS8z00PfVyZ59S4HQZEaTrjemwVNwo0cEE" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:yqEjmAJYDXhs3IVPiRN7AyTHy5vj3W8s0hXYnY-mw7k" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1", + "type" : { + "coding" : [ + { + "code" : "source-artifact", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:xQYRW8dFjjHC1ngz7sgpqn83gnGiw7wXcHAHwdynsIU" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-recording-document", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-recording-document" + ] + }, + "resourceType" : "DocumentReference", + "status" : "current", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "type" : { + "coding" : [ + { + "code" : "location-track-samples", + "system" : "https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format" + } + ] + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:sopJ7r7cGsB8SNRwgrDDfVIxQdh4Yi0qsGv_-ewUKhw" + } + } + ], + "fullUrl" : "urn:uuid:67ee594f-5491-5c52-b199-eb7fb534436c", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:sopJ7r7cGsB8SNRwgrDDfVIxQdh4Yi0qsGv_-ewUKhw" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:keGqikaVp1KtP-VTXpXOgfrMY3JhLPacllBRGwnm0XA" + } + } + ], + "fullUrl" : "urn:uuid:81a02ecd-3890-5159-9e08-a92d1ff34063", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:keGqikaVp1KtP-VTXpXOgfrMY3JhLPacllBRGwnm0XA" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:SBfJSawsIM7ABTa02UUwQX4uz0AfvVzCOluHfM5zcm0" + } + } + ], + "fullUrl" : "urn:uuid:7df29fa2-86f9-5ea8-a447-48cda6aae354", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:SBfJSawsIM7ABTa02UUwQX4uz0AfvVzCOluHfM5zcm0" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:81a02ecd-3890-5159-9e08-a92d1ff34063" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:s6mSUHde0SIpXeVJUkt29HnsauT6t_jVKVJw-KRRbK0" + } + } + ], + "fullUrl" : "urn:uuid:18fba38a-2ee6-5140-80f2-d84f938266b4", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:s6mSUHde0SIpXeVJUkt29HnsauT6t_jVKVJw-KRRbK0" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "iPhone17,1", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "26.1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:cipjXhgIzQYdg8Q3ubLkiAipoA0S6MXNH1ydOvAju78" + } + } + ], + "fullUrl" : "urn:uuid:d21d9031-3216-5431-b57f-1b2afa147c46", + "resource" : { + "deviceName" : [ + { + "name" : "Example Writer", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:cipjXhgIzQYdg8Q3ubLkiAipoA0S6MXNH1ydOvAju78" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.example.writer" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:18fba38a-2ee6-5140-80f2-d84f938266b4" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "42" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:mSNfHxeSGmyJTAPs4LVAyM78MTqcuojPlBm0PeCQh94" + } + } + ], + "fullUrl" : "urn:uuid:e961aa09-3fec-59b1-aab9-bb89371fb1d5", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:7df29fa2-86f9-5ea8-a447-48cda6aae354" + } + } + ], + "entity" : [ + { + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "author", + "display" : "Author", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:d21d9031-3216-5431-b57f-1b2afa147c46" + } + } + ], + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:BXZhB-YbBLS8z00PfVyZ59S4HQZEaTrjemwVNwo0cEE" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:e2805cbe-fbd0-5906-a03c-9b2ab1409bc0" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:63" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-blank-name-with-sync-identity.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-blank-name-with-sync-identity.json new file mode 100644 index 000000000..8ea6a71d3 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-blank-name-with-sync-identity.json @@ -0,0 +1,470 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:oei9-WTo3ZQOm6GXsGzyba5wfb8WXJ5EVOnfhLGpSCU" + } + } + ], + "fullUrl" : "urn:uuid:4144d1e7-84d9-5f2b-a350-43608cf12bc7", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "device" : { + "reference" : "urn:uuid:d956312f-4c23-50db-bc14-90e022e6d814" + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + }, + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-writer-record-version", + "valueString" : "3" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:SCRk4OXXsW9n_6oPuSi5S5a6zV81Hfny2vUBe8XTKt0" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:oei9-WTo3ZQOm6GXsGzyba5wfb8WXJ5EVOnfhLGpSCU" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/writer-record/test/1", + "type" : { + "coding" : [ + { + "code" : "writer-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:vIfSIjXEDH2sYfmrl7Plzyh6_3t3FdXKG5O2EZe5vpQ" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:1XDSeObjR4wlja2kFFTrRkw6CjO32UYij_6RBdfOQbI" + } + } + ], + "fullUrl" : "urn:uuid:d956312f-4c23-50db-bc14-90e022e6d814", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:1XDSeObjR4wlja2kFFTrRkw6CjO32UYij_6RBdfOQbI" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:l4j_qZ5lQY0AmQsSnbkwKRVsnLJVZRnLdCwNqyQD1sA" + } + } + ], + "fullUrl" : "urn:uuid:712f7b9b-943e-5588-b83b-1c5af97b4595", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:l4j_qZ5lQY0AmQsSnbkwKRVsnLJVZRnLdCwNqyQD1sA" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:W53r-MeL3d96IfkBs_sLWCZSjxsSTg37XRyYv-W1c44" + } + } + ], + "fullUrl" : "urn:uuid:5b5d1798-36d7-57b0-adb4-7a6a686629ca", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:W53r-MeL3d96IfkBs_sLWCZSjxsSTg37XRyYv-W1c44" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:712f7b9b-943e-5588-b83b-1c5af97b4595" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:6DhtOZZUHam5W-HohrMT03HiDwOtqyCz2kkm2RveF08" + } + } + ], + "fullUrl" : "urn:uuid:80e3273c-3d80-5579-81d1-8e3a68996d21", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:5b5d1798-36d7-57b0-adb4-7a6a686629ca" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:SCRk4OXXsW9n_6oPuSi5S5a6zV81Hfny2vUBe8XTKt0" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:4144d1e7-84d9-5f2b-a350-43608cf12bc7" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:27" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-device-classification-without-recording-device.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-device-classification-without-recording-device.json new file mode 100644 index 000000000..237981a51 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-device-classification-without-recording-device.json @@ -0,0 +1,350 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:YU4KNVWRqlp9mfF8E5Hpl-8cZ_v8_2XLdpuWi3I7vtg" + } + } + ], + "fullUrl" : "urn:uuid:a86c10b2-c5d4-5e32-b20a-acf1f3d92c1b", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:KvwGqiFmJzXnyA32l_7VSMr9nQsORddnye-BgiPFpg0" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:YU4KNVWRqlp9mfF8E5Hpl-8cZ_v8_2XLdpuWi3I7vtg" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:u9JvTYLnr4RT7IvVJoJgb76cGDJ-tfwIHsqeaQrBSBE" + } + } + ], + "fullUrl" : "urn:uuid:f44a6514-7428-56e9-83e4-5c7ca029fe50", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:u9JvTYLnr4RT7IvVJoJgb76cGDJ-tfwIHsqeaQrBSBE" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:-CyTyjpnePQUmb6-iYUJ-SQLUuAbAHLvYKiaBYtxpwg" + } + } + ], + "fullUrl" : "urn:uuid:cc6451d0-7738-56a2-8df2-ab4cbdc8d4a6", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:-CyTyjpnePQUmb6-iYUJ-SQLUuAbAHLvYKiaBYtxpwg" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:f44a6514-7428-56e9-83e4-5c7ca029fe50" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:ncffhtB0LmRQ-DLjRLey7L3i4VlOmWYwtH27V2AwN-8" + } + } + ], + "fullUrl" : "urn:uuid:31bc8e36-6ffe-5852-8126-3c045cfee93a", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:cc6451d0-7738-56a2-8df2-ab4cbdc8d4a6" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:KvwGqiFmJzXnyA32l_7VSMr9nQsORddnye-BgiPFpg0" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:a86c10b2-c5d4-5e32-b20a-acf1f3d92c1b" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:26" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-device-classification.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-device-classification.json new file mode 100644 index 000000000..6f6dd8a84 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-device-classification.json @@ -0,0 +1,470 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:mFNEqBFhJaRsanQgDqFYN3IQM_vyL46YEvVV1uWOyw8" + } + } + ], + "fullUrl" : "urn:uuid:1f546d61-156c-5bf0-80d4-95941c18de10", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "device" : { + "reference" : "urn:uuid:4d25df34-97c0-5441-a4e4-74e7de79ed10" + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:81UrlZhjo86nQB0UCszGzlJj2_LcPZVTZ_vC9OUQg3w" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:mFNEqBFhJaRsanQgDqFYN3IQM_vyL46YEvVV1uWOyw8" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:KOTseOdrwvtSgbaOq5n_Uytq3S3yzISvXl3KuiKTqFc" + } + } + ], + "fullUrl" : "urn:uuid:4d25df34-97c0-5441-a4e4-74e7de79ed10", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:KOTseOdrwvtSgbaOq5n_Uytq3S3yzISvXl3KuiKTqFc" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:uTK8EAl121dqWmzpnRKwr2aIjkjsxLoOMGHTbDWuxe8" + } + } + ], + "fullUrl" : "urn:uuid:695eb08b-1ea0-57d4-ba75-ef39692fb400", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:uTK8EAl121dqWmzpnRKwr2aIjkjsxLoOMGHTbDWuxe8" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:YhDFNeOk54-8CpHFrvZQ58vSLNo5h_95dRECs3Iv05g" + } + } + ], + "fullUrl" : "urn:uuid:bdd116c3-04dd-5a9e-83c8-047e61d5efbc", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:YhDFNeOk54-8CpHFrvZQ58vSLNo5h_95dRECs3Iv05g" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:695eb08b-1ea0-57d4-ba75-ef39692fb400" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:s1ogOnWed3FyGnYBJya1g9QukiBLlM6Q7ZoPtgsSvEg" + } + } + ], + "fullUrl" : "urn:uuid:85f263ec-1ec6-58b5-887b-39cb81f5c339", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:bdd116c3-04dd-5a9e-83c8-047e61d5efbc" + } + } + ], + "entity" : [ + { + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "author", + "display" : "Author", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:4d25df34-97c0-5441-a4e4-74e7de79ed10" + } + } + ], + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:81UrlZhjo86nQB0UCszGzlJj2_LcPZVTZ_vC9OUQg3w" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:1f546d61-156c-5bf0-80d4-95941c18de10" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:25" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-foreign-application.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-foreign-application.json new file mode 100644 index 000000000..6b5ab372c --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-foreign-application.json @@ -0,0 +1,606 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:pqCLAAGFRwSLHZRIbv_m2xU_YzPozJNYZbzOJe4paZI" + } + } + ], + "fullUrl" : "urn:uuid:a95889d1-0d54-516b-a6a9-a52b2bb1809f", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "device" : { + "reference" : "urn:uuid:0d697d80-71e1-5ba7-a59c-41877b725984" + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:AJz4f8aqK4pJ400P46nAgpmEFAIsR2Ysx4Q2mjQi_vo" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:pqCLAAGFRwSLHZRIbv_m2xU_YzPozJNYZbzOJe4paZI" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:nRttzmH0-qkfZHsgJN7-w0HnszZ1o6dXmcMq1nirLxo" + } + } + ], + "fullUrl" : "urn:uuid:0d697d80-71e1-5ba7-a59c-41877b725984", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:nRttzmH0-qkfZHsgJN7-w0HnszZ1o6dXmcMq1nirLxo" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:R8jE6x3KkPw3WilQx6hegDC7fpB79JyXiIxA2ymK6t0" + } + } + ], + "fullUrl" : "urn:uuid:caa54c64-62e2-5f87-8a52-d461ce1e3265", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:R8jE6x3KkPw3WilQx6hegDC7fpB79JyXiIxA2ymK6t0" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:m8Bs7JWk3X2B-rQkZWnNXymQNjLxPLYM0j_6n_lhCG4" + } + } + ], + "fullUrl" : "urn:uuid:acec87ec-7a33-5a2e-8eb0-ba6e5c2da101", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:m8Bs7JWk3X2B-rQkZWnNXymQNjLxPLYM0j_6n_lhCG4" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:caa54c64-62e2-5f87-8a52-d461ce1e3265" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:HA3QVfGVZkJ_eAJqmDQrBdEo-IavSPptqY5CoENRS-k" + } + } + ], + "fullUrl" : "urn:uuid:6dda8ddb-7e62-5220-b3be-1bda46fc5607", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:HA3QVfGVZkJ_eAJqmDQrBdEo-IavSPptqY5CoENRS-k" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "iPhone17,1", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "26.1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:MuXiWtyyfMnkHkYaZ_QJitDcMiXEFWtxTLwxVJcyYIQ" + } + } + ], + "fullUrl" : "urn:uuid:4b4f451f-5741-5465-9043-2565a381e500", + "resource" : { + "deviceName" : [ + { + "name" : "Example Writer", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:MuXiWtyyfMnkHkYaZ_QJitDcMiXEFWtxTLwxVJcyYIQ" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.example.writer" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:6dda8ddb-7e62-5220-b3be-1bda46fc5607" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "42" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:GJUFtSA2PpuSNCivubyOax0xETJQUdwOLYHifg5CfqQ" + } + } + ], + "fullUrl" : "urn:uuid:ed4de8c5-4bf5-5b2f-b948-5592de94fe86", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:acec87ec-7a33-5a2e-8eb0-ba6e5c2da101" + } + } + ], + "entity" : [ + { + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "author", + "display" : "Author", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:4b4f451f-5741-5465-9043-2565a381e500" + } + } + ], + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:AJz4f8aqK4pJ400P46nAgpmEFAIsR2Ysx4Q2mjQi_vo" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:a95889d1-0d54-516b-a6a9-a52b2bb1809f" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:20" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-host-equals-converter-host.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-host-equals-converter-host.json new file mode 100644 index 000000000..297ca949d --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-host-equals-converter-host.json @@ -0,0 +1,548 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:N1bsPg5Tpt9wBEW0ki5-9c1RxomFVnpucNSIymcJKFQ" + } + } + ], + "fullUrl" : "urn:uuid:5599a011-2c26-59bb-a95c-40de982c2253", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "device" : { + "reference" : "urn:uuid:9274a9b9-9a8b-5efc-af2d-304e81d0b30e" + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:XmujUDtBGLEON9ZBNR4qUb1jXIXyx_J8pugN6uU1dvo" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:N1bsPg5Tpt9wBEW0ki5-9c1RxomFVnpucNSIymcJKFQ" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:5GB6sZS_7W5Cgk-hDHObBDOz89ZpPK6EkdTRyahQK1o" + } + } + ], + "fullUrl" : "urn:uuid:9274a9b9-9a8b-5efc-af2d-304e81d0b30e", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:5GB6sZS_7W5Cgk-hDHObBDOz89ZpPK6EkdTRyahQK1o" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:w3TNXrnA2C6WOf_hwvPqROcYiOlEqWVdnCx1uQrEGcc" + } + } + ], + "fullUrl" : "urn:uuid:43810cf8-8b6e-51f8-853b-664c10277672", + "resource" : { + "deviceName" : [ + { + "name" : "Phone", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:w3TNXrnA2C6WOf_hwvPqROcYiOlEqWVdnCx1uQrEGcc" + } + ], + "manufacturer" : "Apple", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "iPhone17,1", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "26.1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:VmrsaBJYNbc7lxK9uRsEZEblajKYCiXbzGxNr90XCSY" + } + } + ], + "fullUrl" : "urn:uuid:64a0a45c-e646-56fe-9e28-1b3c15a5ffeb", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:VmrsaBJYNbc7lxK9uRsEZEblajKYCiXbzGxNr90XCSY" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:43810cf8-8b6e-51f8-853b-664c10277672" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:L-7r74u94S5VQCgUyZqLO8yPIUvCmcsNpTlwDPgkPpI" + } + } + ], + "fullUrl" : "urn:uuid:a7bdd03c-01d1-5fa1-b065-2b5de07354d1", + "resource" : { + "deviceName" : [ + { + "name" : "Example Writer", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:L-7r74u94S5VQCgUyZqLO8yPIUvCmcsNpTlwDPgkPpI" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.example.writer" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:43810cf8-8b6e-51f8-853b-664c10277672" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "42" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:wlYCKpots3JoMUyqic3U1zXALPxy_jai82eZsLplroo" + } + } + ], + "fullUrl" : "urn:uuid:99b14254-dd46-5ebd-9052-73e667e3b3fc", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:64a0a45c-e646-56fe-9e28-1b3c15a5ffeb" + } + } + ], + "entity" : [ + { + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "author", + "display" : "Author", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:a7bdd03c-01d1-5fa1-b065-2b5de07354d1" + } + } + ], + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:XmujUDtBGLEON9ZBNR4qUb1jXIXyx_J8pugN6uU1dvo" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:5599a011-2c26-59bb-a95c-40de982c2253" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:24" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-self-build-equals-revision.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-self-build-equals-revision.json new file mode 100644 index 000000000..002d142ff --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-self-build-equals-revision.json @@ -0,0 +1,618 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:H7yUNVraO2BUJOM7_QY4twfGRocBMc5GOJLwytTksFU" + } + } + ], + "fullUrl" : "urn:uuid:92465a78-7a3f-5726-b1d7-ee1018ef2f3e", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "device" : { + "reference" : "urn:uuid:f7ccb2bb-0bff-5730-bd5d-48e573cf3d89" + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:4zOLoSjizi6BxZ461XZTg0Pr2wtZNXXm5c7SEudypKY" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:H7yUNVraO2BUJOM7_QY4twfGRocBMc5GOJLwytTksFU" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:XMmeXu7fRyMFrccTwdG0A5d_kJlKHeLCvXAr_Dws_WE" + } + } + ], + "fullUrl" : "urn:uuid:f7ccb2bb-0bff-5730-bd5d-48e573cf3d89", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:XMmeXu7fRyMFrccTwdG0A5d_kJlKHeLCvXAr_Dws_WE" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:DWkZy6qN7lDWGCWE9njA9MDWwL9msiQziGy4cqGqM9s" + } + } + ], + "fullUrl" : "urn:uuid:85fe11f2-bc5b-5b0f-abe3-5908657e664b", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:DWkZy6qN7lDWGCWE9njA9MDWwL9msiQziGy4cqGqM9s" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:YwtHrVoKW5NfFHYkdhvQcEwiPXKdBnVv-aPn1f27dQY" + } + } + ], + "fullUrl" : "urn:uuid:94382637-b141-5b78-9506-125b8fa7cd3d", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:YwtHrVoKW5NfFHYkdhvQcEwiPXKdBnVv-aPn1f27dQY" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:85fe11f2-bc5b-5b0f-abe3-5908657e664b" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.2.3" + }, + { + "type" : { + "coding" : [ + { + "code" : "build", + "display" : "Build", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "42" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:6mgRqjetEQP6M-CXoG17XC93bgw47v5zuZIurjpzziQ" + } + } + ], + "fullUrl" : "urn:uuid:854722cb-9bca-5eb9-af52-e2c354f18ef8", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:6mgRqjetEQP6M-CXoG17XC93bgw47v5zuZIurjpzziQ" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "iPhone17,1", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "26.1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:_ZBfe7GNZUCKegUJ1CKITz5rpxGaOeSHeXQQ6wurRE8" + } + } + ], + "fullUrl" : "urn:uuid:d2533d04-4857-5137-9ef6-f3b3b3437eec", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:_ZBfe7GNZUCKegUJ1CKITz5rpxGaOeSHeXQQ6wurRE8" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:854722cb-9bca-5eb9-af52-e2c354f18ef8" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "42" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:eJji_kYGToL221Hus9hjiXNDYXjkmObR0nsAZ1ow7KI" + } + } + ], + "fullUrl" : "urn:uuid:4031c305-e90a-56fa-87c3-286b4612aaa8", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:94382637-b141-5b78-9506-125b8fa7cd3d" + } + } + ], + "entity" : [ + { + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "author", + "display" : "Author", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:d2533d04-4857-5137-9ef6-f3b3b3437eec" + } + } + ], + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:4zOLoSjizi6BxZ461XZTg0Pr2wtZNXXm5c7SEudypKY" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:92465a78-7a3f-5726-b1d7-ee1018ef2f3e" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:21" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-self-older-build.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-self-older-build.json new file mode 100644 index 000000000..3e958b22d --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-self-older-build.json @@ -0,0 +1,618 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:s4xlxhafc7RsPl_wQ-b96kSjFg2rXZuCIG3Hbw2Ew_o" + } + } + ], + "fullUrl" : "urn:uuid:45e6f1e8-2b41-5524-9794-097e83de95f2", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "device" : { + "reference" : "urn:uuid:1e4f60d6-f4a3-54ce-a5f9-235bf0c932f7" + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:EoaAO9mXym31Kh5UIGSlE-QHb5JwLtXWVZ9ufV2JhrQ" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:s4xlxhafc7RsPl_wQ-b96kSjFg2rXZuCIG3Hbw2Ew_o" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:AuzFJ5dzw_Eea3WwhGBPaljG9MmXkooCE6UTFnJa6O0" + } + } + ], + "fullUrl" : "urn:uuid:1e4f60d6-f4a3-54ce-a5f9-235bf0c932f7", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:AuzFJ5dzw_Eea3WwhGBPaljG9MmXkooCE6UTFnJa6O0" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:FjfcSkiI7TKf0tpVXF45anjKiUaIuLOhHuMMXD27T6w" + } + } + ], + "fullUrl" : "urn:uuid:f9b5d32c-fb8f-52dd-a414-35abda9d39db", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:FjfcSkiI7TKf0tpVXF45anjKiUaIuLOhHuMMXD27T6w" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:jMhsNHOkjaC9W-H2TWIJOJm1mTt6jf__smVZEM9xWhE" + } + } + ], + "fullUrl" : "urn:uuid:43352af1-c8d5-5a6d-9982-3192be805f9f", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:jMhsNHOkjaC9W-H2TWIJOJm1mTt6jf__smVZEM9xWhE" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:f9b5d32c-fb8f-52dd-a414-35abda9d39db" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.2.3" + }, + { + "type" : { + "coding" : [ + { + "code" : "build", + "display" : "Build", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "43" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Ab2HWd0MFBIc2-14EWGLAoWaIoGf55n-NPD_X3JdvNQ" + } + } + ], + "fullUrl" : "urn:uuid:09c85600-150d-54d4-91d1-fdf5ca024fe6", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Ab2HWd0MFBIc2-14EWGLAoWaIoGf55n-NPD_X3JdvNQ" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "iPhone17,1", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "26.1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:sCSyThEwHrA-QNutyWoT8IvqvObAfx9iVgwMMjwgBlw" + } + } + ], + "fullUrl" : "urn:uuid:98fa6785-6ecf-5477-81e8-43671d56b65c", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:sCSyThEwHrA-QNutyWoT8IvqvObAfx9iVgwMMjwgBlw" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:09c85600-150d-54d4-91d1-fdf5ca024fe6" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "42" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:kbmN3MLnZKwnlRzRuF0935Jq1RMgTFqWExpXKPYuZZw" + } + } + ], + "fullUrl" : "urn:uuid:2cf28482-aa74-5f3e-9642-94909fbf9b82", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:43352af1-c8d5-5a6d-9982-3192be805f9f" + } + } + ], + "entity" : [ + { + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "author", + "display" : "Author", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:98fa6785-6ecf-5477-81e8-43671d56b65c" + } + } + ], + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:EoaAO9mXym31Kh5UIGSlE-QHb5JwLtXWVZ9ufV2JhrQ" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:45e6f1e8-2b41-5524-9794-097e83de95f2" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:22" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-self-token-identical.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-self-token-identical.json new file mode 100644 index 000000000..2666a904b --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-self-token-identical.json @@ -0,0 +1,470 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:vdd9BSjfFviTjyD8wkjFrlxpgvGd0nHijXDFBU4aEVI" + } + } + ], + "fullUrl" : "urn:uuid:6a599798-b1c3-5d65-bd14-8afd4d896374", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "device" : { + "reference" : "urn:uuid:f98c822b-f8b0-563c-a61d-16342d6d3e43" + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:UtyKmuNmZRtWC6Cb1iDLm9WSCg6brTP-ItN7sd1HhBE" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:vdd9BSjfFviTjyD8wkjFrlxpgvGd0nHijXDFBU4aEVI" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:YQJIbbB8nuB0-RPnkaOOBSVaBuHjGSfhNNc4uwOODSc" + } + } + ], + "fullUrl" : "urn:uuid:f98c822b-f8b0-563c-a61d-16342d6d3e43", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:YQJIbbB8nuB0-RPnkaOOBSVaBuHjGSfhNNc4uwOODSc" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:duxmSr3Uxe-v-wJgeIcbhR64QQ7n3jy0TUBxvljFuaE" + } + } + ], + "fullUrl" : "urn:uuid:417e9464-bb22-56ae-8bc4-58910aed36ce", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:duxmSr3Uxe-v-wJgeIcbhR64QQ7n3jy0TUBxvljFuaE" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:ETsCwd__V6NpQJf6VOxp0GvIf0JmozLFJ8URnCefuk8" + } + } + ], + "fullUrl" : "urn:uuid:9f7774ef-99d1-57a1-8d3f-3d62a9055a0c", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:ETsCwd__V6NpQJf6VOxp0GvIf0JmozLFJ8URnCefuk8" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:417e9464-bb22-56ae-8bc4-58910aed36ce" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "42" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:lIUFjhANW3jap4BH1HLWUDLDPsNFnc5_hrANCOu7zuA" + } + } + ], + "fullUrl" : "urn:uuid:4153f2f4-6bcb-5340-b209-f375de0c4a76", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:9f7774ef-99d1-57a1-8d3f-3d62a9055a0c" + } + } + ], + "entity" : [ + { + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "author", + "display" : "Author", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:9f7774ef-99d1-57a1-8d3f-3d62a9055a0c" + } + } + ], + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:UtyKmuNmZRtWC6Cb1iDLm9WSCg6brTP-ItN7sd1HhBE" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:6a599798-b1c3-5d65-bd14-8afd4d896374" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:23" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-without-version.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-without-version.json new file mode 100644 index 000000000..4c8f1f554 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-without-version.json @@ -0,0 +1,592 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:71A8Gf5aQhQ_33O72ULGDB1iiEJi-ds1MChFYa6UtZE" + } + } + ], + "fullUrl" : "urn:uuid:e2dff379-9ae2-59e9-8ef6-57d88010ca64", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "device" : { + "reference" : "urn:uuid:673eb625-bb2a-5a9f-8be4-671921b101a8" + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:pu9X9aITPkaZSwzXq0rNXketNBHLqnK_XJaLomKFdWs" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:71A8Gf5aQhQ_33O72ULGDB1iiEJi-ds1MChFYa6UtZE" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:45Uc_1_gwHsuABUimsyG1CL6Q_MEbWP1FAubfEtm6j8" + } + } + ], + "fullUrl" : "urn:uuid:673eb625-bb2a-5a9f-8be4-671921b101a8", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:45Uc_1_gwHsuABUimsyG1CL6Q_MEbWP1FAubfEtm6j8" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:BtKDCQ-8uHZTri3NWIuleHdsbXZY6cyoialzqVtyubM" + } + } + ], + "fullUrl" : "urn:uuid:bbba67f6-f6eb-5258-9f0b-9b89e14e786b", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:BtKDCQ-8uHZTri3NWIuleHdsbXZY6cyoialzqVtyubM" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:xrE6K8oKqbR1QnI3GZOJVDEyFiwiWhMkrQDLlbVFyu0" + } + } + ], + "fullUrl" : "urn:uuid:1fa02907-e6d9-58c2-9f33-a839357070ba", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:xrE6K8oKqbR1QnI3GZOJVDEyFiwiWhMkrQDLlbVFyu0" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:bbba67f6-f6eb-5258-9f0b-9b89e14e786b" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:3ntQLUR90EZUNsD1WNW60LY9c_USs_Z3DD47ED6vTZk" + } + } + ], + "fullUrl" : "urn:uuid:70151851-1494-57d5-a18e-9c62a5f04d94", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:3ntQLUR90EZUNsD1WNW60LY9c_USs_Z3DD47ED6vTZk" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "iPhone17,1", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "26.1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:bVGe5u0L2gfNRE-aE7WuRImncvimhcHXi6DoTHn9-CA" + } + } + ], + "fullUrl" : "urn:uuid:1eef1284-4494-52d0-b506-99f73e87783a", + "resource" : { + "deviceName" : [ + { + "name" : "Example Writer", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:bVGe5u0L2gfNRE-aE7WuRImncvimhcHXi6DoTHn9-CA" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.example.writer" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:70151851-1494-57d5-a18e-9c62a5f04d94" + }, + "resourceType" : "Device", + "status" : "active" + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:DsAvQCF-363X2Y682oZ4QRF-_yer9cjN2enmmah5yTo" + } + } + ], + "fullUrl" : "urn:uuid:e9e34d14-0317-5207-81ad-9abae89e4c8b", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:1fa02907-e6d9-58c2-9f33-a839357070ba" + } + } + ], + "entity" : [ + { + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "author", + "display" : "Author", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:1eef1284-4494-52d0-b506-99f73e87783a" + } + } + ], + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:pu9X9aITPkaZSwzXq0rNXketNBHLqnK_XJaLomKFdWs" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:e2dff379-9ae2-59e9-8ef6-57d88010ca64" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:28" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift b/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift new file mode 100644 index 000000000..310887544 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift @@ -0,0 +1,163 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +import HealthKit +import ObjectiveC + + +/// TEST-ONLY. Builds HealthKit samples the way the store hands them back: with a chosen UUID, an +/// attributable `HKSourceRevision`, and (for the series classes HealthKit offers no synthetic +/// initializer for) chosen dates, device and metadata. +/// +/// HealthKit's public factories mint a fresh UUID and attribute every sample to the running +/// process, so no test can otherwise pin a graph whose identities derive from the UUID, or one that +/// carries writer and writer-host Device entries. The helper writes HealthKit's private ivars +/// through key-value coding (`_UUID`, `_sourceRevision`, ...); such a sample behaves like a fetched +/// one, including through an `NSKeyedArchiver` round trip. `StoredSampleFixturesTests` fails, and +/// never skips, the moment HealthKit stops honoring a key, so a silent regression into +/// process-attributed samples cannot hide behind green goldens. +/// +/// Nothing here may be used outside the test target. +enum StoredSampleFixtures { + /// The writer a stored sample is attributed to, as `HKSourceRevision` states it. + struct Writer: Sendable { + /// A source without a name or bundle identifier, which the converter treats as no writer at all; what a + /// sample built in-process reports when nothing attributes it. + static let unattributed = Writer(name: "", bundleIdentifier: "", version: nil, productType: nil) + + var name: String + var bundleIdentifier: String + var version: String? + var productType: String? + var operatingSystemVersion = OperatingSystemVersion(majorVersion: 26, minorVersion: 1, patchVersion: 0) + } + + /// The facts of a sample whose class has no public initializer (`HKHeartbeatSeriesSample`, + /// `HKElectrocardiogram`, `HKWorkoutRoute`). + struct SeriesShape: Sendable { + var uuid: UUID + var start: Date + var end: Date + var device: HKDevice? + var metadata: [String: any Sendable]? // swiftlint:disable:this discouraged_optional_collection + var writer: Writer + } + + enum FixtureError: Error, CustomStringConvertible { + case classNotConstructible(String) + case keyNotHonored(key: String, class: String) + + var description: String { + switch self { + case .classNotConstructible(let name): + "HealthKit refused to allocate a bare \(name); the stored-sample fixtures need a new strategy" + case let .keyNotHonored(key, name): + "\(name) no longer reads back the value written to '\(key)'; the stored-sample fixtures need a new strategy" + } + } + } + + private static let objectKeys = ["UUID", "sourceRevision", "device", "metadata"] + private static let sampleKeys = ["sampleType", "startTimestamp", "endTimestamp"] + + /// An `HKSource` naming the writing application; HealthKit itself only ever vends one for the running process. + static func source(name: String, bundleIdentifier: String) throws -> HKSource { + let source = try allocate(HKSource.self) + try write(name, to: "name", of: source) + try write(bundleIdentifier, to: "bundleIdentifier", of: source) + return unsafeDowncast(source, to: HKSource.self) + } + + static func sourceRevision(_ writer: Writer) throws -> HKSourceRevision { + HKSourceRevision( + source: try source(name: writer.name, bundleIdentifier: writer.bundleIdentifier), + version: writer.version, + productType: writer.productType, + operatingSystemVersion: writer.operatingSystemVersion + ) + } + + /// `sample` with the UUID the store would have given it and, when `writer` is given, its source revision; + /// every other fact stays as built. + /// + /// Without a writer the sample keeps the revision its factory gave it, which names no source at all. That is + /// the only shape `HKCorrelation`'s initializer admits for its objects: one that already states a writer is + /// validated against the process's default source, which a test process does not have. + static func stored(_ sample: Sample, uuid: UUID, writer: Writer? = nil) throws -> Sample { + try write(uuid, to: "UUID", of: sample) + if let writer { + try write(try sourceRevision(writer), to: "sourceRevision", of: sample) + } + try verify(sample, uuid: uuid, writer: writer) + return sample + } + + /// A bare instance of a sample class without a public initializer, carrying exactly `shape`. + static func seriesSample(_ type: Sample.Type, sampleType: HKSampleType, shape: SeriesShape) throws -> Sample { + let object = try allocate(type) + try write(sampleType, to: "sampleType", of: object) + try write(NSNumber(value: shape.start.timeIntervalSinceReferenceDate), to: "startTimestamp", of: object) + try write(NSNumber(value: shape.end.timeIntervalSinceReferenceDate), to: "endTimestamp", of: object) + try write(shape.device, to: "device", of: object) + try write(shape.metadata, to: "metadata", of: object) + let sample = try stored(unsafeDowncast(object, to: type), uuid: shape.uuid, writer: shape.writer) + guard sample.sampleType == sampleType, sample.startDate == shape.start, sample.endDate == shape.end else { + throw FixtureError.keyNotHonored(key: "sampleType/startTimestamp/endTimestamp", class: String(describing: type)) + } + guard sample.device == shape.device, (sample.metadata ?? [:]).keys.sorted() == (shape.metadata ?? [:]).keys.sorted() else { + throw FixtureError.keyNotHonored(key: "device/metadata", class: String(describing: type)) + } + return sample + } + + /// Whether every private ivar the fixtures write still exists, checked before a single value is written. + static func privateStorageIsPresent() -> Bool { + (objectKeys.allSatisfy { class_getInstanceVariable(HKObject.self, "_\($0)") != nil }) + && (sampleKeys.allSatisfy { class_getInstanceVariable(HKSample.self, "_\($0)") != nil }) + && ["name", "bundleIdentifier"].allSatisfy { class_getInstanceVariable(HKSource.self, "_\($0)") != nil } + } + + private static func allocate(_ type: AnyClass) throws -> NSObject { + guard let object = class_createInstance(type, 0) as? NSObject else { + throw FixtureError.classNotConstructible(String(describing: type)) + } + return object + } + + private static func write(_ value: Any?, to key: String, of object: NSObject) throws { + guard class_getInstanceVariable(type(of: object), "_\(key)") != nil else { + throw FixtureError.keyNotHonored(key: key, class: String(describing: type(of: object))) + } + object.setValue(value, forKey: key) + } + + private static func verify(_ sample: HKSample, uuid: UUID, writer: Writer?) throws { + let name = String(describing: type(of: sample)) + guard sample.uuid == uuid else { + throw FixtureError.keyNotHonored(key: "UUID", class: name) + } + guard let writer else { + return + } + let revision = sample.sourceRevision + guard revision.source.name == writer.name, + revision.source.bundleIdentifier == writer.bundleIdentifier, + revision.version == writer.version, + revision.productType == writer.productType, + revision.operatingSystemVersion.majorVersion == writer.operatingSystemVersion.majorVersion, + revision.operatingSystemVersion.minorVersion == writer.operatingSystemVersion.minorVersion, + revision.operatingSystemVersion.patchVersion == writer.operatingSystemVersion.patchVersion else { + throw FixtureError.keyNotHonored(key: "sourceRevision", class: name) + } + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/StoredSampleFixturesTests.swift b/Tests/GroveHealthKitFHIRTests/StoredSampleFixturesTests.swift new file mode 100644 index 000000000..848d1cb13 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/StoredSampleFixturesTests.swift @@ -0,0 +1,124 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit +import ModelsR4 +import Testing + + +/// Proves the stored-sample trick still works on this HealthKit, and fails rather than skips when it stops working: +/// every golden rests on the chosen UUID and writer actually reaching the converter. +@Suite +struct StoredSampleFixturesTests { + private static let uuid = GoldenFixtures.uuid(0xF0) + private static let writer = GoldenFixtures.foreignWriter + + private static func expectStored(_ sample: HKSample, sourceLocation: SourceLocation = #_sourceLocation) throws { + #expect(sample.uuid == uuid, sourceLocation: sourceLocation) + let revision = sample.sourceRevision + #expect(revision.source.name == writer.name, sourceLocation: sourceLocation) + #expect(revision.source.bundleIdentifier == writer.bundleIdentifier, sourceLocation: sourceLocation) + #expect(revision.version == writer.version, sourceLocation: sourceLocation) + #expect(revision.productType == writer.productType, sourceLocation: sourceLocation) + #expect(revision.operatingSystemVersion.majorVersion == 26, sourceLocation: sourceLocation) + #expect(revision.operatingSystemVersion.minorVersion == 1, sourceLocation: sourceLocation) + #expect(revision.operatingSystemVersion.patchVersion == 0, sourceLocation: sourceLocation) + } + + private static func archived(_ sample: HKSample, as type: Sample.Type) throws -> Sample { + let data = try NSKeyedArchiver.archivedData(withRootObject: sample, requiringSecureCoding: true) + let restored = try NSKeyedUnarchiver.unarchivedObject(ofClass: type, from: data) + return try #require(restored) + } + + @Test("HealthKit still has the private storage the fixtures write") + func privateStorageIsPresent() { + #expect(StoredSampleFixtures.privateStorageIsPresent()) + } + + @Test("A sample from a public initializer takes the chosen UUID and writer, and keeps them through an archive") + func publicInitializerSamplesAreStorable() throws { + let sample = try GoldenFixtures.heartRate(uuid: Self.uuid, device: GoldenFixtures.watch, writer: Self.writer) + try Self.expectStored(sample) + #expect(sample.quantity.doubleValue(for: GoldenFixtures.beatsPerMinute) == 72) + #expect(sample.device == GoldenFixtures.watch) + #expect(sample.metadata?[HKMetadataKeyTimeZone] as? String == GoldenFixtures.timeZone) + + let restored = try Self.archived(sample, as: HKQuantitySample.self) + try Self.expectStored(restored) + #expect(restored.device?.localIdentifier == GoldenFixtures.watch.localIdentifier) + #expect(restored.metadata?[HKMetadataKeyTimeZone] as? String == GoldenFixtures.timeZone) + + let category = try GoldenFixtures.category(.sleepAnalysis, value: 1, uuid: Self.uuid, duration: 60) + #expect(category.uuid == Self.uuid) + let correlation = try GoldenCase.bloodPressure() + #expect(correlation.uuid == GoldenFixtures.uuid(9)) + #expect(correlation.objects.map(\.uuid).sorted { $0.uuidString < $1.uuidString } == [GoldenFixtures.uuid(0x91), GoldenFixtures.uuid(0x92)]) + let workout = try StoredSampleFixtures.stored(try GoldenFixtures.workout(withEvents: true), uuid: Self.uuid, writer: Self.writer) + try Self.expectStored(workout) + #expect(workout.workoutEvents?.count == 12) + } + + @Test("A series class without a public initializer takes every fact of its shape, and keeps them through an archive") + func seriesSamplesAreConstructible() throws { + let shape = GoldenCase.seriesShape(uuid: 0xF0, duration: 30) + let series = try StoredSampleFixtures.seriesSample(HKHeartbeatSeriesSample.self, sampleType: HKSeriesType.heartbeat(), shape: shape) + let ecg = try StoredSampleFixtures.seriesSample(HKElectrocardiogram.self, sampleType: HKObjectType.electrocardiogramType(), shape: shape) + let route = try StoredSampleFixtures.seriesSample(HKWorkoutRoute.self, sampleType: HKSeriesType.workoutRoute(), shape: shape) + for sample in [series, ecg, route] as [HKSample] { + try Self.expectStored(sample) + #expect(sample.startDate == shape.start) + #expect(sample.endDate == shape.end) + #expect(sample.device == shape.device) + #expect(sample.metadata?[HKMetadataKeyTimeZone] as? String == GoldenFixtures.timeZone) + } + #expect(series.sampleType == HKSeriesType.heartbeat()) + #expect(ecg.sampleType == HKObjectType.electrocardiogramType()) + #expect(route.sampleType == HKSeriesType.workoutRoute()) + #expect(HealthKitSourceType(series) == .heartbeatSeries) + #expect(HealthKitSourceType(ecg) == .electrocardiogram) + #expect(HealthKitSourceType(route) == .workoutRoute) + + let restored = try Self.archived(series, as: HKHeartbeatSeriesSample.self) + try Self.expectStored(restored) + #expect(restored.startDate == shape.start) + #expect(restored.sampleType == HKSeriesType.heartbeat()) + } + + @Test("The chosen UUID and writer are what the converter sees") + func converterReadsTheStoredFacts() throws { + let sample = try GoldenFixtures.heartRate(uuid: Self.uuid, device: GoldenFixtures.watch, writer: Self.writer) + let context = try GoldenFixtures.context(sequence: 250) + let conversion = try HealthKitConverter().convert(sample, context: context).primary + + #expect(conversion.source.uuid == Self.uuid) + let expectedRecord = try context.event.identityScope.sourceRecord( + adapterID: HealthKitConverter.adapterID, + sourceType: HealthKitSourceType.heartRate.rawValue, + repositoryScope: context.event.repositoryScope, + nativeRecordID: Self.uuid.uuidString.lowercased() + ).identifier + #expect(conversion.identifiers.sourceRecord == expectedRecord) + + let writerSnapshot = try #require(conversion.identifiers.writerSnapshot) + let writer = try #require(conversion.graph.resource(Device.self, at: writerSnapshot)) + #expect(writer.deviceName?.first?.name.value?.string == Self.writer.name) + #expect(writer.identifier?.last?.value?.value?.string == Self.writer.bundleIdentifier) + let writerHostSnapshot = try #require(conversion.identifiers.writerHostSnapshot) + let writerHost = try #require(conversion.graph.resource(Device.self, at: writerHostSnapshot)) + #expect(writerHost.modelNumber?.value?.string == Self.writer.productType) + #expect(writerHost.version?.first?.value.value?.string == "26.1.0") + } +} + +#endif From e9dc69b6596ccbf5e5651484d4457e8fd519a4ee Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sat, 3 Oct 2026 12:43:37 +0200 Subject: [PATCH 003/220] Add the Exchange Producer, Event Sequencer and Public Graph Bytes Expose each exchange graph's validated bytes (sorted keys, unescaped slashes) and a validating initializer for received bytes, nest the graph kind, and add the shared producer configuration, the Grove-owned event sequencer with app-supplied storage and keyed in-flight reservations, a one-call identity-scope initializer, and an ASCII millisecond instant formatter. The earlier spellings stay as deprecated forwards. Co-Authored-By: Claude Fable 5.1 --- .../GroveFHIRContract/ExchangeEventKey.swift | 80 +++++ .../ExchangeEventSequencer+State.swift | 83 +++++ .../ExchangeEventSequencer.swift | 180 ++++++++++ .../ExchangeGraph+Equality.swift | 4 +- .../ExchangeGraph+EventPolicy.swift | 2 +- .../ExchangeGraph+SerializedPolicy.swift | 4 +- Sources/GroveFHIRContract/ExchangeGraph.swift | 94 +++-- .../GroveFHIRContract/ExchangeInstant.swift | 112 ++++++ .../GroveFHIRContract/ExchangeProducer.swift | 86 +++++ .../OpaqueIdentityError.swift | 6 +- .../OpaqueIdentityScope.swift | 24 ++ .../ConversionThroughputBenchmark.swift | 2 +- .../ExchangeEventSequencerTests.swift | 325 ++++++++++++++++++ .../ExchangeGraphBytesTests.swift | 116 +++++++ ...ExchangeGraphValidationDocumentTests.swift | 4 +- .../ExchangeInstantTests.swift | 179 ++++++++++ .../ExchangeProducerTests.swift | 213 ++++++++++++ .../GoldenGraphTests.swift | 8 +- 18 files changed, 1476 insertions(+), 46 deletions(-) create mode 100644 Sources/GroveFHIRContract/ExchangeEventKey.swift create mode 100644 Sources/GroveFHIRContract/ExchangeEventSequencer+State.swift create mode 100644 Sources/GroveFHIRContract/ExchangeEventSequencer.swift create mode 100644 Sources/GroveFHIRContract/ExchangeInstant.swift create mode 100644 Sources/GroveFHIRContract/ExchangeProducer.swift create mode 100644 Tests/GroveHealthKitFHIRTests/ExchangeEventSequencerTests.swift create mode 100644 Tests/GroveHealthKitFHIRTests/ExchangeGraphBytesTests.swift create mode 100644 Tests/GroveHealthKitFHIRTests/ExchangeInstantTests.swift create mode 100644 Tests/GroveHealthKitFHIRTests/ExchangeProducerTests.swift diff --git a/Sources/GroveFHIRContract/ExchangeEventKey.swift b/Sources/GroveFHIRContract/ExchangeEventKey.swift new file mode 100644 index 000000000..92c4b79e9 --- /dev/null +++ b/Sources/GroveFHIRContract/ExchangeEventKey.swift @@ -0,0 +1,80 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(CryptoKit) +import CryptoKit +#else +import Crypto +#endif +package import Foundation + + +/// What a key holds while it is reserved: the event's sequence and the instant it was reserved at. +package struct ExchangeEventReservation: Hashable, Codable, Sendable { + private enum CodingKeys: String, CodingKey { + case sequence + case instantMilliseconds + } + + package let sequence: EventSequence + /// The caller's instant at reservation, at millisecond precision, the same on every return of the key. + package let instant: Date + + init(_ stored: ExchangeEventSequencer.State.Reservation) { + self.sequence = EventSequence(stored.sequence) + self.instant = ExchangeInstant.date(millisecondsSinceEpoch: stored.instantMilliseconds) + } + + package init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self.sequence = try EventSequence(container.decode(String.self, forKey: .sequence)) + self.instant = ExchangeInstant.date(millisecondsSinceEpoch: try container.decode(Int64.self, forKey: .instantMilliseconds)) + } + + package func encode(to encoder: any Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(sequence.rawValue, forKey: .sequence) + try container.encode(ExchangeInstant.millisecondsSinceEpoch(instant), forKey: .instantMilliseconds) + } +} + + +/// The key one exchange event is reserved under: deterministic for one source-record version, and +/// opaque, so the ledger holds no clear record identity. +package struct ExchangeEventKey: Hashable, Codable, Sendable { + package let rawValue: String +} + + +extension ExchangeEventKey { + /// The key of one source record's event under one adapter. + /// + /// SHA-256, base64url without padding, over the length-framed UTF-8 parts `grove-event-key-v0`, + /// the kind (`active` or `retraction`), the adapter id, the source-record identifier value and, + /// when the source versions its records, the revision evidence: a re-recorded record is a new + /// event, an active event and its retraction never share a reservation. + /// + /// - Precondition: Every part is shorter than 4 GiB. + package init(kind: ExchangeGraph.Kind, adapterID: String, sourceRecord: String, revision: String? = nil) { + let kindLabel = switch kind { + case .active: "active" + case .retraction: "retraction" + } + var parts = ["grove-event-key-v0", kindLabel, adapterID, sourceRecord] + if let revision { + parts.append(revision) + } + let framed: Data + do { + framed = try LengthFramedUTF8.encode(parts) + } catch { + preconditionFailure("An event key part exceeds the framing limit: \(error)") + } + self.rawValue = Data(SHA256.hash(data: framed)).base64URLEncodedStringWithoutPadding + } +} diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer+State.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer+State.swift new file mode 100644 index 000000000..877d0c415 --- /dev/null +++ b/Sources/GroveFHIRContract/ExchangeEventSequencer+State.swift @@ -0,0 +1,83 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +import Foundation + + +extension ExchangeEventSequencer { + /// The persisted ledger: the producer instance, the next sequence, and the keyed reservations. + /// + /// Stored as JSON under a schema version, so a later layout is recognised rather than misread. + struct State: Codable, Equatable, Sendable { + /// One key's reservation, with every instant as whole milliseconds since 1970-01-01T00:00:00Z. + struct Reservation: Codable, Equatable, Sendable { + let sequence: UInt64 + let instantMilliseconds: Int64 + /// When the reservation was made, for retention; the same instant the reservation hands out. + let reservedAtMilliseconds: Int64 + } + + static let currentSchemaVersion: UInt = 1 + + let schemaVersion: UInt + let producerInstance: UUID + var nextSequence: UInt64 + var reservations: [String: Reservation] + + /// A fresh ledger under a new producer instance, numbering from one. + init() { + self.schemaVersion = Self.currentSchemaVersion + self.producerInstance = UUID() + self.nextSequence = 1 + self.reservations = [:] + } + + /// The stored ledger, or `nil` for an empty storage. + static func decode(_ data: Data?) throws -> State? { + guard let data else { + return nil + } + let state = try JSONDecoder().decode(State.self, from: data) + guard state.schemaVersion == currentSchemaVersion else { + throw StateError.unsupportedSchemaVersion(state.schemaVersion) + } + return state + } + + func encoded() throws -> Data { + try JSONEncoder().encode(self) + } + + /// The key's reservation, or a new one under the next sequence. + mutating func reservation(for key: ExchangeEventKey, instantMilliseconds: Int64) throws -> Reservation { + if let existing = reservations[key.rawValue] { + return existing + } + let (next, overflow) = nextSequence.addingReportingOverflow(1) + guard !overflow else { + throw StateError.sequencesExhausted + } + let reservation = Reservation( + sequence: nextSequence, + instantMilliseconds: instantMilliseconds, + reservedAtMilliseconds: instantMilliseconds + ) + nextSequence = next + reservations[key.rawValue] = reservation + return reservation + } + + /// Forgets every reservation made before `cutoff`; `nil` keeps them all. + mutating func prune(reservedBefore cutoff: Int64?) { + guard let cutoff, reservations.contains(where: { $0.value.reservedAtMilliseconds < cutoff }) else { + return + } + reservations = reservations.filter { $0.value.reservedAtMilliseconds >= cutoff } + } + } +} diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift new file mode 100644 index 000000000..78d93d35c --- /dev/null +++ b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift @@ -0,0 +1,180 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +public import Foundation + + +/// Hands out exchange-event sequences under one producer instance. +/// +/// Grove owns the logic; the application supplies durable storage through ``Storage``. The sequencer +/// mints the producer instance on first use and persists it with the counter, so every event an +/// installation emits is numbered under one instance until the storage is reset, after which a new +/// instance starts at one and no sequence is reused under the old one. +/// +/// Exporters reserve a sequence per event key before building the event and release the key once the +/// source has durably acknowledged the event. A key that is still reserved returns its reservation +/// unchanged, so an exact redelivery after a crash reproduces the same event; a reservation that is +/// never released is forgotten after ``Retention/maximumAge``. +public final class ExchangeEventSequencer: Sendable { + /// Durable, atomic read-modify-write of one opaque blob. + /// + /// A conformance makes the replacement durable before `update` returns and serialises concurrent + /// callers (a lock, an actor hop or a database transaction). The bytes are the sequencer's own; + /// a conformance stores them unchanged and never interprets them. + public protocol Storage: Sendable { + /// Loads the stored blob, lets `body` replace it, persists the replacement and returns `body`'s result. + /// + /// `nil` is what an empty storage loads; a `body` that throws stores nothing. + func update(_ body: (inout Data?) throws -> R) throws -> R + } + + /// How long a reservation that is never released is kept. + public struct Retention: Hashable, Sendable { + /// Thirty days: long enough for a source to redeliver after a crash, short enough that + /// keys which were never released do not accumulate for the life of an installation. + public static let `default` = Retention(maximumAge: 30 * 24 * 60 * 60) + + /// A reservation made further than this before a later reservation's instant is forgotten + /// at that later reservation; its key then reserves a new sequence. + public let maximumAge: TimeInterval + + /// A retention of `maximumAge` seconds; `.infinity` keeps every reservation until it is released. + public init(maximumAge: TimeInterval) { + precondition(maximumAge > 0, "A reservation is retained for a positive duration.") + self.maximumAge = maximumAge + } + } + + /// Faults in the stored ledger itself; what a ``Storage`` throws propagates unchanged. + public enum StateError: Error, Equatable, Sendable { + /// The ledger was written by a schema this version does not read. + case unsupportedSchemaVersion(UInt) + /// Every sequence under this producer instance has been handed out. + case sequencesExhausted + } + + /// Process-local storage: nothing survives the process, so every launch is a new producer instance. + private final class MemoryStorage: Storage { + private let lock = NSLock() + nonisolated(unsafe) private var data: Data? + + func update(_ body: (inout Data?) throws -> R) throws -> R { + lock.lock() + defer { lock.unlock() } + return try body(&data) + } + } + + /// How long a reservation that is never released is kept. + public let retention: Retention + + private let storage: any Storage + /// Serialises this sequencer's own read-modify-write cycles; several sequencers over one storage + /// rely on that storage's serialisation. + private let lock = NSLock() + + /// The installation's producer instance, minted and persisted on first use. + public var producerInstance: UUID { + get throws { + try withState { $0.producerInstance } + } + } + + /// Creates a sequencer over the application's storage. + /// + /// Nothing is read here; the stored ledger is loaded, and any storage error surfaces, on first use. + public init(storage: any Storage, retention: Retention = .default) { + self.storage = storage + self.retention = retention + } + + /// A sequencer whose ledger lives in this process only, for tests and previews. + public static func inMemory(retention: Retention = .default) -> ExchangeEventSequencer { + ExchangeEventSequencer(storage: MemoryStorage(), retention: retention) + } + + /// Loads the ledger, creating it when the storage is empty, and stores it back when `body` changed it. + private func withState(_ body: (inout State) throws -> R) throws -> R { + lock.lock() + defer { lock.unlock() } + return try storage.update { data in + let loaded = try State.decode(data) + var state = loaded ?? State() + let result = try body(&state) + if state != loaded { + data = try state.encoded() + } + return result + } + } + + /// Mutates a ledger that exists; an empty storage is left empty. + private func withExistingState(_ body: (inout State) throws -> Void) throws { + lock.lock() + defer { lock.unlock() } + try storage.update { data in + guard let loaded = try State.decode(data) else { + return + } + var state = loaded + try body(&state) + if state != loaded { + data = try state.encoded() + } + } + } +} + + +extension ExchangeEventSequencer { + /// One reservation per key, in the keys' order. + /// + /// A key that is still reserved returns its existing reservation, the same sequence and the same + /// instant, so an exact redelivery reproduces the event. A new key takes the next sequence and + /// `instant` at millisecond precision. Duplicate keys in one call map to one reservation. + /// Reservations older than the retention, measured from `instant`, are forgotten first. Every + /// reservation is durable before this returns, and a sequence is never handed out twice. + package func reserve(_ keys: [ExchangeEventKey], at instant: Date) throws -> [ExchangeEventReservation] { + let instantMilliseconds = ExchangeInstant.millisecondsSinceEpoch(instant) + let cutoff = retentionCutoff(before: instantMilliseconds) + return try withState { state in + state.prune(reservedBefore: cutoff) + var reservations: [ExchangeEventReservation] = [] + reservations.reserveCapacity(keys.count) + for key in keys { + let stored = try state.reservation(for: key, instantMilliseconds: instantMilliseconds) + reservations.append(ExchangeEventReservation(stored)) + } + return reservations + } + } + + /// Forgets the reservations of these keys; a key that holds none is ignored. + package func release(_ keys: [ExchangeEventKey]) throws { + try withExistingState { state in + for key in keys { + state.reservations.removeValue(forKey: key.rawValue) + } + } + } + + /// ``release(_:)`` for a commit action that cannot act on a failure: a reservation that stays + /// behind is harmless, as a redelivery reproduces its event and retention forgets it eventually. + package func releaseIgnoringErrors(_ keys: [ExchangeEventKey]) { + try? release(keys) + } + + /// The instant before which a reservation is forgotten, or `nil` when the retention never expires. + private func retentionCutoff(before instantMilliseconds: Int64) -> Int64? { + guard let maximumAge = Int64(exactly: (retention.maximumAge * 1000).rounded(.up)) else { + return nil + } + let (cutoff, overflow) = instantMilliseconds.subtractingReportingOverflow(maximumAge) + return overflow ? nil : cutoff + } +} diff --git a/Sources/GroveFHIRContract/ExchangeGraph+Equality.swift b/Sources/GroveFHIRContract/ExchangeGraph+Equality.swift index 238c839c6..df197e93b 100644 --- a/Sources/GroveFHIRContract/ExchangeGraph+Equality.swift +++ b/Sources/GroveFHIRContract/ExchangeGraph+Equality.swift @@ -265,8 +265,8 @@ extension ExchangeGraph { /// text, so `72` and `72.0` are different content. A retry that is equal under this comparison /// is the exact retry the exchange protocol admits. public func isSemanticallyEqual(to other: ExchangeGraph) -> Bool { - guard let lhs = try? LosslessJSONValue(parsing: jsonData), - let rhs = try? LosslessJSONValue(parsing: other.jsonData) else { + guard let lhs = try? LosslessJSONValue(parsing: json), + let rhs = try? LosslessJSONValue(parsing: other.json) else { return false } return lhs == rhs diff --git a/Sources/GroveFHIRContract/ExchangeGraph+EventPolicy.swift b/Sources/GroveFHIRContract/ExchangeGraph+EventPolicy.swift index 37fb4104f..8c818e316 100644 --- a/Sources/GroveFHIRContract/ExchangeGraph+EventPolicy.swift +++ b/Sources/GroveFHIRContract/ExchangeGraph+EventPolicy.swift @@ -41,7 +41,7 @@ extension ExchangeGraph { } static func validateEntryResourcePolicy( - kind: ExchangeGraphKind, + kind: Kind, entries: [BundleEntry], document: ValidationDocument ) throws(ExchangeGraphError) { diff --git a/Sources/GroveFHIRContract/ExchangeGraph+SerializedPolicy.swift b/Sources/GroveFHIRContract/ExchangeGraph+SerializedPolicy.swift index f9b936ed3..a1a31f013 100644 --- a/Sources/GroveFHIRContract/ExchangeGraph+SerializedPolicy.swift +++ b/Sources/GroveFHIRContract/ExchangeGraph+SerializedPolicy.swift @@ -12,7 +12,7 @@ import ModelsR4 extension ExchangeGraph { static func validateSerializedEntryPolicy( - kind: ExchangeGraphKind, + kind: Kind, json: Result ) throws(ExchangeGraphError) { let root = try serializedBundleObject(json) @@ -49,7 +49,7 @@ extension ExchangeGraph { private static func validateSerializedEntry( _ entry: [String: Any], - kind: ExchangeGraphKind, + kind: Kind, activeTypes: Set ) throws(ExchangeGraphError) { guard let resource = entry["resource"] as? [String: Any], diff --git a/Sources/GroveFHIRContract/ExchangeGraph.swift b/Sources/GroveFHIRContract/ExchangeGraph.swift index 407cea94f..1b927e798 100644 --- a/Sources/GroveFHIRContract/ExchangeGraph.swift +++ b/Sources/GroveFHIRContract/ExchangeGraph.swift @@ -10,20 +10,9 @@ public import Foundation public import ModelsR4 -/// The semantic kind of a complete Grove exchange graph. -public enum ExchangeGraphKind: Hashable, Sendable { - case active - case retraction - - var profile: FHIRPrimitive { - switch self { - case .active: - Profile.groveMobileExchangeBundle - case .retraction: - GroveLifecycleContract.retractionBundleProfile - } - } -} +/// The semantic kind of a complete Grove exchange graph; the kind now lives at ``ExchangeGraph/Kind``. +@available(*, deprecated, renamed: "ExchangeGraph.Kind", message: "Compatibility spelling; removed with the exporter rework's final cleanup.") +public typealias ExchangeGraphKind = ExchangeGraph.Kind /// The one authoritative, validated value emitted by a Grove producer. @@ -31,22 +20,54 @@ public enum ExchangeGraphKind: Hashable, Sendable { /// Entries are owned only by the Bundle. Producers may expose stable entry keys, but do not retain /// independent mutable resource copies that can drift from what is serialized and uploaded. /// The graph keeps the JSON it was validated from, so ``isSemanticallyEqual(to:)`` decides over -/// lossless tokens rather than over a model that has already normalized decimal lexemes. +/// lossless tokens rather than over a model that has already normalized decimal lexemes, and so a +/// consumer uploads exactly what was validated: ``json``. public struct ExchangeGraph: Sendable { - public let kind: ExchangeGraphKind + /// The semantic kind of a complete Grove exchange graph. + public enum Kind: Hashable, Sendable { + case active + case retraction + + var profile: FHIRPrimitive { + switch self { + case .active: + Profile.groveMobileExchangeBundle + case .retraction: + GroveLifecycleContract.retractionBundleProfile + } + } + } + + /// Sorted members and unescaped slashes: the same tokens the default encoder emits, in one + /// member order in every process, so a retry reproduces the bytes and a stored graph diffs by content. + private static var wireEncoder: JSONEncoder { + let encoder = JSONEncoder() + encoder.outputFormatting = [.sortedKeys, .withoutEscapingSlashes] + return encoder + } + + public let kind: Kind public let eventIdentifier: ExchangeEventIdentifier public let bundle: ModelsR4.Bundle - let jsonData: Data + /// The serialized graph exactly as it was validated. + /// + /// A graph built from a model holds that model's canonical encoding (sorted members, slashes + /// unescaped); a graph re-validated from stored bytes holds those bytes unchanged. Upload and + /// persist these bytes, not a re-encoding of ``bundle``. + public let json: Data + + /// The event's business identifier, as `Bundle.identifier` states it. + public var event: BusinessIdentifier { eventIdentifier.identifier.identifier } public init( - kind: ExchangeGraphKind, + kind: Kind, eventIdentifier: ExchangeEventIdentifier, bundle: ModelsR4.Bundle ) throws(ExchangeGraphError) { - self.jsonData = try Self.drainingTemporaries { () throws(ExchangeGraphError) in - let jsonData: Data + self.json = try Self.drainingTemporaries { () throws(ExchangeGraphError) in + let json: Data do { - jsonData = try JSONEncoder().encode(bundle) + json = try Self.wireEncoder.encode(bundle) } catch { throw .invalidEntries(String(reflecting: type(of: error))) } @@ -54,33 +75,42 @@ public struct ExchangeGraph: Sendable { kind: kind, eventIdentifier: eventIdentifier, bundle: bundle, - document: ValidationDocument(bundle: bundle, jsonData: jsonData) + document: ValidationDocument(bundle: bundle, jsonData: json) ) - return jsonData + return json } self.kind = kind self.eventIdentifier = eventIdentifier self.bundle = bundle } - /// Re-validates stored or received JSON before it is trusted again. + /// Re-validates stored or received JSON before it is trusted again, and keeps exactly those bytes as ``json``. /// /// Serialized checks run first, because Foundation keeps only one of duplicate members and /// decoding through `Foundation.URL` could normalize an identity system or collapse a /// prohibited resource type before the model sees it. public init( - kind: ExchangeGraphKind, - jsonData: Data + validating json: Data, + kind: Kind ) throws(ExchangeGraphError) { (self.eventIdentifier, self.bundle) = try Self.drainingTemporaries { () throws(ExchangeGraphError) in - try Self.decodeValidated(kind: kind, jsonData: jsonData) + try Self.decodeValidated(kind: kind, jsonData: json) } self.kind = kind - self.jsonData = jsonData + self.json = json + } + + /// ``init(validating:kind:)`` under its earlier spelling. + @available(*, deprecated, renamed: "init(validating:kind:)", message: "Compatibility spelling; removed with the exporter rework's final cleanup.") + public init( + kind: Kind, + jsonData: Data + ) throws(ExchangeGraphError) { + try self.init(validating: jsonData, kind: kind) } private static func decodeValidated( - kind: ExchangeGraphKind, + kind: Kind, jsonData: Data ) throws(ExchangeGraphError) -> (ExchangeEventIdentifier, ModelsR4.Bundle) { do { @@ -140,7 +170,7 @@ public struct ExchangeGraph: Sendable { } private static func validate( - kind: ExchangeGraphKind, + kind: Kind, eventIdentifier: ExchangeEventIdentifier, bundle: ModelsR4.Bundle, document: ValidationDocument @@ -187,7 +217,7 @@ public struct ExchangeGraph: Sendable { private static func validatedEntries( _ bundle: ModelsR4.Bundle, - kind: ExchangeGraphKind + kind: Kind ) throws(ExchangeGraphError) -> [BundleEntry] { let profiles = bundle.meta?.profile ?? [] let exchangeProfiles = [Profile.groveMobileExchangeBundle, GroveLifecycleContract.retractionBundleProfile] @@ -221,7 +251,7 @@ public struct ExchangeGraph: Sendable { } private static func validateLifecycle( - kind: ExchangeGraphKind, + kind: Kind, entries: [BundleEntry], document: ValidationDocument ) throws(ExchangeGraphError) { diff --git a/Sources/GroveFHIRContract/ExchangeInstant.swift b/Sources/GroveFHIRContract/ExchangeInstant.swift new file mode 100644 index 000000000..cd111ed07 --- /dev/null +++ b/Sources/GroveFHIRContract/ExchangeInstant.swift @@ -0,0 +1,112 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +package import Foundation +package import ModelsR4 + + +/// Converter clock instants as the wire states them: UTC, millisecond precision, ASCII. +/// +/// The lexeme is computed from the instant's own binary64 value with integer arithmetic over the +/// proleptic Gregorian calendar, never through a `Formatter`, `Calendar` or `Locale`, so the same +/// instant yields the same bytes in every process, on every platform, under every locale. +/// Milliseconds are rounded half to even, trailing fraction zeros are dropped, and a whole second +/// carries no fraction: `2026-10-03T10:30:00Z`, `…:00.5Z`, `…:00.251Z`. +package enum ExchangeInstant { + private struct CivilDate { + let year: Int64 + let month: Int64 + let day: Int64 + } + + /// `Date` counts from 2001-01-01T00:00:00Z; the wire counts from 1970. + private static let referenceEpochMilliseconds: Int64 = 978_307_200_000 + + /// The instant as a FHIR `instant` lexeme in UTC. + package static func utcLexeme(_ date: Date) -> String { + let (days, millisecondOfDay) = floorDivide(millisecondsSinceEpoch(date), by: 86_400_000) + let civil = civilDate(fromDays: days) + let secondOfDay = millisecondOfDay / 1000 + let millisecond = millisecondOfDay % 1000 + var lexeme = "" + lexeme.reserveCapacity(24) + lexeme += padded(civil.year, width: 4) + lexeme += "-" + padded(civil.month, width: 2) + "-" + padded(civil.day, width: 2) + lexeme += "T" + padded(secondOfDay / 3600, width: 2) + lexeme += ":" + padded(secondOfDay / 60 % 60, width: 2) + lexeme += ":" + padded(secondOfDay % 60, width: 2) + if millisecond != 0 { + var fraction = padded(millisecond, width: 3) + while fraction.hasSuffix("0") { + fraction.removeLast() + } + lexeme += "." + fraction + } + lexeme += "Z" + return lexeme + } + + /// The instant as a FHIR `Instant`, which keeps the parsed lexeme and prints it back verbatim. + package static func fhirInstant(_ date: Date) throws -> Instant { + try Instant(utcLexeme(date)) + } + + /// The instant as a FHIR `DateTime`, which keeps the parsed lexeme and prints it back verbatim. + package static func fhirDateTime(_ date: Date) throws -> DateTime { + try DateTime(utcLexeme(date)) + } + + /// Milliseconds since 1970-01-01T00:00:00Z, rounded half to even from the instant's own binary64 value. + /// + /// A non-finite or out-of-range instant saturates; its lexeme then names no FHIR-representable year. + static func millisecondsSinceEpoch(_ date: Date) -> Int64 { + let scaled = (date.timeIntervalSinceReferenceDate * 1000).rounded(.toNearestOrEven) + let sinceReference = Int64(exactly: scaled) ?? (scaled < 0 ? .min : .max) + let (sum, overflow) = sinceReference.addingReportingOverflow(referenceEpochMilliseconds) + return overflow ? .max : sum + } + + /// The instant at exactly these milliseconds since 1970-01-01T00:00:00Z. + /// + /// Round-trips through ``millisecondsSinceEpoch(_:)``: the nearest binary64 second count is within + /// a fraction of a millisecond of the exact value, so rounding recovers the same count. + static func date(millisecondsSinceEpoch milliseconds: Int64) -> Date { + let (sinceReference, overflow) = milliseconds.subtractingReportingOverflow(referenceEpochMilliseconds) + return Date(timeIntervalSinceReferenceDate: Double(overflow ? .min : sinceReference) / 1000) + } + + private static func floorDivide(_ value: Int64, by divisor: Int64) -> (quotient: Int64, remainder: Int64) { + var quotient = value / divisor + var remainder = value % divisor + if remainder < 0 { + quotient -= 1 + remainder += divisor + } + return (quotient, remainder) + } + + /// Days since 1970-01-01 to a proleptic Gregorian date (Howard Hinnant's `civil_from_days`). + private static func civilDate(fromDays days: Int64) -> CivilDate { + let shifted = days + 719_468 + let era = (shifted >= 0 ? shifted : shifted - 146_096) / 146_097 + let dayOfEra = shifted - era * 146_097 + let yearOfEra = (dayOfEra - dayOfEra / 1460 + dayOfEra / 36_524 - dayOfEra / 146_096) / 365 + let dayOfYear = dayOfEra - (365 * yearOfEra + yearOfEra / 4 - yearOfEra / 100) + let shiftedMonth = (5 * dayOfYear + 2) / 153 + let day = dayOfYear - (153 * shiftedMonth + 2) / 5 + 1 + let month = shiftedMonth < 10 ? shiftedMonth + 3 : shiftedMonth - 9 + return CivilDate(year: yearOfEra + era * 400 + (month <= 2 ? 1 : 0), month: month, day: day) + } + + /// ASCII decimal digits, zero-padded to `width`; `String(_:)` never consults the locale. + private static func padded(_ value: Int64, width: Int) -> String { + let digits = String(value.magnitude) + let zeros = String(repeating: "0", count: max(0, width - digits.count)) + return (value < 0 ? "-" : "") + zeros + digits + } +} diff --git a/Sources/GroveFHIRContract/ExchangeProducer.swift b/Sources/GroveFHIRContract/ExchangeProducer.swift new file mode 100644 index 000000000..71f7477cc --- /dev/null +++ b/Sources/GroveFHIRContract/ExchangeProducer.swift @@ -0,0 +1,86 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +/// Who is exporting: one deployment, one participant, one application installation. +/// +/// Immutable; rebuild it when any input changes. The inputs every event shares are checked once +/// here, so a deployment fault is reported where the producer is configured rather than inside a +/// conversion, and the sequencer numbers every event the producer emits under one producer instance. +public final class ExchangeProducer: Sendable { + /// A configuration the producer refuses, as every event built under it would be refused. + public enum ConfigurationError: Error, Equatable, Sendable { + /// The subject's pseudonym is numbered in one of the deployment's own graph identity systems. + case reservedSubjectIdentifierSystem(IdentifierSystem) + /// A study or enrollment identifier is numbered in one of the deployment's own graph identity systems. + case reservedStudyIdentifierSystem(IdentifierSystem) + /// Two enrollments name the same study. + case duplicateStudy(BusinessIdentifier) + /// Two enrollments carry the same enrollment identifier. + case duplicateEnrollment(BusinessIdentifier) + + /// The registered diagnostic: every configuration fault is a deployment defect. + public var diagnostic: ProducerDiagnostic { + ExchangeGraphRule.mobileInputUnclassified.diagnostic(at: "ExchangeProducer") + } + } + + /// The deployment's scope that mints every opaque identity. + public let identityScope: OpaqueIdentityScope + /// The participant every event is about. + public let subject: Subject + /// The converting application, as its Device snapshot states it. + public let application: ApplicationDevice + /// The host the application runs on, as captured when the producer was built. + public let host: HostDevice + /// The participant's known enrollments, each study once. + public let studies: [StudyEnrollment] + /// Where the producer's events take their sequences from. + public let sequencer: ExchangeEventSequencer + + /// Creates the producer of one installation. + /// + /// - Parameters: + /// - identityScope: The deployment's scope that mints every opaque identity. + /// - subject: The participant every event is about. + /// - application: The converting application, as its Device snapshot states it. + /// - host: The host the application runs on; captured now, as a later snapshot may differ. + /// - studies: The participant's known enrollments, each study once. + /// - sequencer: Where the producer's events take their sequences from. + public init( + identityScope: OpaqueIdentityScope, + subject: Subject, + application: ApplicationDevice, + host: HostDevice = .current(), + studies: [StudyEnrollment] = [], + sequencer: ExchangeEventSequencer + ) throws(ConfigurationError) { + let reserved = identityScope.systems.all + guard !reserved.contains(subject.identifier.system) else { + throw .reservedSubjectIdentifierSystem(subject.identifier.system) + } + var seenStudies: Set = [] + var seenEnrollments: Set = [] + for enrollment in studies { + for identifier in [enrollment.study, enrollment.enrollment] where reserved.contains(identifier.system) { + throw .reservedStudyIdentifierSystem(identifier.system) + } + guard seenStudies.insert(enrollment.study).inserted else { + throw .duplicateStudy(enrollment.study) + } + guard seenEnrollments.insert(enrollment.enrollment).inserted else { + throw .duplicateEnrollment(enrollment.enrollment) + } + } + self.identityScope = identityScope + self.subject = subject + self.application = application + self.host = host + self.studies = studies + self.sequencer = sequencer + } +} diff --git a/Sources/GroveFHIRContract/OpaqueIdentityError.swift b/Sources/GroveFHIRContract/OpaqueIdentityError.swift index f2b67a726..8814e320a 100644 --- a/Sources/GroveFHIRContract/OpaqueIdentityError.swift +++ b/Sources/GroveFHIRContract/OpaqueIdentityError.swift @@ -11,6 +11,8 @@ /// A component fault names the component by its path, `.` as the catalog spells them. public enum OpaqueIdentityError: Error, Equatable, Sendable { case invalidKeyID(String) + /// The exchange protocol's recommended identifier systems cannot be formed under this deployment root. + case invalidDeploymentRoot(String) case keyTooShort(actualBytes: Int) case publishedConformanceKeyProhibited /// A component the identity kind requires is empty. @@ -33,8 +35,8 @@ public enum OpaqueIdentityError: Error, Equatable, Sendable { ExchangeGraphRule.mobileInputRequiredMetadataMissing.diagnostic(at: path) case .nonCanonicalPartIndex(let path): ExchangeGraphRule.mobileInputUnclassified.diagnostic(at: path) - case .invalidKeyID, .keyTooShort, .publishedConformanceKeyProhibited, .invalidCodeToken, .providerKindRequired, - .reusedIdentifierSystem, .componentTooLarge, .invalidComponentCount: + case .invalidKeyID, .invalidDeploymentRoot, .keyTooShort, .publishedConformanceKeyProhibited, .invalidCodeToken, + .providerKindRequired, .reusedIdentifierSystem, .componentTooLarge, .invalidComponentCount: ExchangeGraphRule.mobileInputUnclassified.diagnostic } } diff --git a/Sources/GroveFHIRContract/OpaqueIdentityScope.swift b/Sources/GroveFHIRContract/OpaqueIdentityScope.swift index 4578ad6b2..457712a2a 100644 --- a/Sources/GroveFHIRContract/OpaqueIdentityScope.swift +++ b/Sources/GroveFHIRContract/OpaqueIdentityScope.swift @@ -51,6 +51,30 @@ public struct OpaqueIdentityScope: Sendable, CustomDebugStringConvertible { ) } + /// Creates the identity scope of one deployment root, with its twelve systems in the exchange + /// protocol's recommended form: ``DeploymentIdentifierSystems/derived(root:keyID:epoch:)`` + /// followed by ``init(systems:keyID:epoch:key:)``. + /// + /// A key id the systems cannot carry is reported as ``OpaqueIdentityError/invalidKeyID(_:)``; + /// a root the recommended form cannot be built under as ``OpaqueIdentityError/invalidDeploymentRoot(_:)``. + public init( + root: IdentifierSystem, + keyID: String, + epoch: EventSequence, + key: SymmetricKey + ) throws(OpaqueIdentityError) { + guard Self.isValidKeyID(keyID) else { + throw .invalidKeyID(keyID) + } + let systems: DeploymentIdentifierSystems + do { + systems = try DeploymentIdentifierSystems.derived(root: root, keyID: keyID, epoch: epoch) + } catch { + throw .invalidDeploymentRoot(root.rawValue) + } + try self.init(systems: systems, keyID: keyID, epoch: epoch, key: key) + } + private init( systems: DeploymentIdentifierSystems, keyID: String, diff --git a/Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark.swift b/Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark.swift index 4242fa3aa..ccd4e0b4c 100644 --- a/Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark.swift +++ b/Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark.swift @@ -316,7 +316,7 @@ struct ConversionThroughputBenchmark { run.report.line("scenario=\(run.name) phase=encode-bundle(sortedKeys+withoutEscapingSlashes) \(run.rate(stagedSeconds)) " + "bytesPerBundle=\(stagedBytes / run.count)") // The graph's stored bytes are the encoder's bytes, so (b) is exactly what the graph already holds. - #expect(run.conversions[0].graph.jsonData.count == encoded[0].count) + #expect(run.conversions[0].graph.json.count == encoded[0].count) run.graphInitSeconds = try Stopwatch.seconds { for conversion in run.conversions { diff --git a/Tests/GroveHealthKitFHIRTests/ExchangeEventSequencerTests.swift b/Tests/GroveHealthKitFHIRTests/ExchangeEventSequencerTests.swift new file mode 100644 index 000000000..9dc467612 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ExchangeEventSequencerTests.swift @@ -0,0 +1,325 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +import Foundation +@testable import GroveFHIRContract +import Synchronization +import Testing + + +/// A storage that keeps the blob in memory, counts its writes, and can be reset or made to fail. +private final class LedgerStorage: ExchangeEventSequencer.Storage { + struct Failure: Error, Equatable {} + + private struct Ledger { + var data: Data? + var writes = 0 + var failing = false + } + + private let state = Mutex(Ledger()) + + var data: Data? { state.withLock { $0.data } } + var writes: Int { state.withLock { $0.writes } } + + func update(_ body: (inout Data?) throws -> R) throws -> R { + try state.withLock { stored in + guard !stored.failing else { + throw Failure() + } + var data = stored.data + let result = try body(&data) + if data != stored.data { + stored.data = data + stored.writes += 1 + } + return result + } + } + + func reset() { + state.withLock { $0 = Ledger(data: nil, writes: $0.writes, failing: false) } + } + + func fail(_ failing: Bool) { + state.withLock { $0.failing = failing } + } + + func seed(_ json: String) { + state.withLock { $0.data = Data(json.utf8) } + } +} + + +@Suite +struct ExchangeEventSequencerTests { + private static let instant = Date(timeIntervalSince1970: 1_791_023_400.251) + + private static func key(_ record: String, kind: ExchangeGraph.Kind = .active, revision: String? = nil) -> ExchangeEventKey { + ExchangeEventKey(kind: kind, adapterID: "healthkit", sourceRecord: record, revision: revision) + } + + @Test("New keys take consecutive sequences in input order, at the millisecond instant") + func newKeysTakeConsecutiveSequences() throws { + let sequencer = ExchangeEventSequencer.inMemory() + let reservations = try sequencer.reserve([Self.key("a"), Self.key("b"), Self.key("c")], at: Self.instant) + #expect(reservations.map(\.sequence.rawValue) == ["1", "2", "3"]) + #expect(reservations.map(\.instant) == Array(repeating: ExchangeInstant.date(millisecondsSinceEpoch: 1_791_023_400_251), count: 3)) + #expect(try sequencer.reserve([Self.key("d")], at: Self.instant).map(\.sequence.rawValue) == ["4"]) + } + + @Test("A reserved key returns the same sequence and instant, whatever the later instant") + func reservedKeyIsReturnedUnchanged() throws { + let sequencer = ExchangeEventSequencer.inMemory() + let first = try sequencer.reserve([Self.key("a")], at: Self.instant) + let again = try sequencer.reserve([Self.key("a")], at: Self.instant.addingTimeInterval(3600)) + #expect(again == first) + #expect(ExchangeInstant.millisecondsSinceEpoch(again[0].instant) == 1_791_023_400_251) + #expect(try sequencer.reserve([Self.key("b")], at: Self.instant).map(\.sequence.rawValue) == ["2"]) + } + + @Test("After release the key takes a new sequence; a sequence is never reused") + func releasedKeyTakesNewSequence() throws { + let sequencer = ExchangeEventSequencer.inMemory() + let first = try sequencer.reserve([Self.key("a"), Self.key("b")], at: Self.instant) + try sequencer.release([Self.key("a")]) + let second = try sequencer.reserve([Self.key("a"), Self.key("b")], at: Self.instant) + #expect(second[0].sequence.rawValue == "3") + #expect(second[1] == first[1]) + try sequencer.release([Self.key("a"), Self.key("b"), Self.key("never-reserved")]) + try sequencer.release([]) + #expect(try sequencer.reserve([Self.key("b")], at: Self.instant).map(\.sequence.rawValue) == ["4"]) + } + + @Test("An active event and its retraction never share a reservation") + func kindsDoNotShareReservations() throws { + let sequencer = ExchangeEventSequencer.inMemory() + let active = Self.key("a", kind: .active) + let retraction = Self.key("a", kind: .retraction) + #expect(active != retraction) + let reservations = try sequencer.reserve([active, retraction], at: Self.instant) + #expect(reservations[0].sequence != reservations[1].sequence) + } + + @Test("Duplicate keys in one call map to one reservation") + func duplicateKeysShareOneReservation() throws { + let sequencer = ExchangeEventSequencer.inMemory() + let reservations = try sequencer.reserve([Self.key("a"), Self.key("a"), Self.key("b"), Self.key("a")], at: Self.instant) + #expect(reservations.map(\.sequence.rawValue) == ["1", "1", "2", "1"]) + #expect(reservations[0] == reservations[1]) + } + + @Test("The producer instance is minted once and shared by every sequencer over the same storage") + func producerInstanceIsStableOverOneStorage() throws { + let storage = LedgerStorage() + let first = ExchangeEventSequencer(storage: storage) + let second = ExchangeEventSequencer(storage: storage) + let instance = try first.producerInstance + #expect(try second.producerInstance == instance) + #expect(try first.producerInstance == instance) + #expect(storage.writes == 1, "the first read persists the minted instance; later reads do not rewrite") + _ = try second.reserve([Self.key("a")], at: Self.instant) + #expect(try ExchangeEventSequencer(storage: storage).producerInstance == instance) + #expect(try ExchangeEventSequencer.inMemory().producerInstance != instance) + } + + @Test("Reservations are durable before reserve returns, and an exact retry does not rewrite the ledger") + func reservationsAreDurable() throws { + let storage = LedgerStorage() + let sequencer = ExchangeEventSequencer(storage: storage) + let reserved = try sequencer.reserve([Self.key("a"), Self.key("b")], at: Self.instant) + #expect(storage.writes == 1) + let fromStorage = try ExchangeEventSequencer(storage: storage).reserve([Self.key("b"), Self.key("a")], at: Self.instant.addingTimeInterval(60)) + #expect(fromStorage == [reserved[1], reserved[0]]) + #expect(storage.writes == 1) + let stored = try #require(storage.data) + let state = try JSONDecoder().decode(ExchangeEventSequencer.State.self, from: stored) + #expect(state.schemaVersion == ExchangeEventSequencer.State.currentSchemaVersion) + #expect(state.nextSequence == 3) + #expect(state.reservations.keys.sorted() == [Self.key("a").rawValue, Self.key("b").rawValue].sorted()) + #expect(state.reservations[Self.key("a").rawValue]?.instantMilliseconds == 1_791_023_400_251) + #expect(state.reservations[Self.key("a").rawValue]?.reservedAtMilliseconds == 1_791_023_400_251) + } + + @Test("A storage that restarts from nil yields a new producer instance numbering from one") + func resetStorageYieldsNewProducerInstance() throws { + let storage = LedgerStorage() + let sequencer = ExchangeEventSequencer(storage: storage) + let before = try sequencer.producerInstance + _ = try sequencer.reserve([Self.key("a"), Self.key("b")], at: Self.instant) + storage.reset() + let after = try sequencer.producerInstance + #expect(after != before) + let reservations = try sequencer.reserve([Self.key("a")], at: Self.instant) + #expect(reservations.map(\.sequence.rawValue) == ["1"]) + #expect(try sequencer.producerInstance == after) + } + + @Test("Reservations older than the retention are forgotten at the next reservation") + func retentionPrunesOldReservations() throws { + let sequencer = ExchangeEventSequencer.inMemory(retention: .init(maximumAge: 60)) + let first = try sequencer.reserve([Self.key("a")], at: Self.instant) + #expect(try sequencer.reserve([Self.key("a")], at: Self.instant.addingTimeInterval(59.999)) == first) + #expect(try sequencer.reserve([Self.key("b")], at: Self.instant.addingTimeInterval(60)).map(\.sequence.rawValue) == ["2"]) + #expect(try sequencer.reserve([Self.key("a")], at: Self.instant.addingTimeInterval(60)) == first, "exactly the retention old is kept") + _ = try sequencer.reserve([Self.key("c")], at: Self.instant.addingTimeInterval(60.001)) + let renewed = try sequencer.reserve([Self.key("a")], at: Self.instant.addingTimeInterval(60.002)) + #expect(renewed[0].sequence.rawValue == "4") + #expect(ExchangeInstant.millisecondsSinceEpoch(renewed[0].instant) == ExchangeInstant.millisecondsSinceEpoch(Self.instant.addingTimeInterval(60.002))) + #expect(try sequencer.reserve([Self.key("b")], at: Self.instant.addingTimeInterval(60.002)).map(\.sequence.rawValue) == ["2"]) + } + + @Test("The default retention keeps a reservation for thirty days") + func defaultRetention() throws { + #expect(ExchangeEventSequencer.Retention.default.maximumAge == 30 * 24 * 60 * 60) + let sequencer = ExchangeEventSequencer.inMemory() + #expect(sequencer.retention == .default) + let first = try sequencer.reserve([Self.key("a")], at: Self.instant) + #expect(try sequencer.reserve([Self.key("a")], at: Self.instant.addingTimeInterval(29 * 24 * 60 * 60)) == first) + _ = try sequencer.reserve([Self.key("b")], at: Self.instant.addingTimeInterval(31 * 24 * 60 * 60)) + #expect(try sequencer.reserve([Self.key("a")], at: Self.instant.addingTimeInterval(31 * 24 * 60 * 60)) != first) + } + + @Test("Storage errors propagate from reserve and release; the ignoring variant swallows them") + func storageErrorsPropagate() throws { + let storage = LedgerStorage() + let sequencer = ExchangeEventSequencer(storage: storage) + _ = try sequencer.reserve([Self.key("a")], at: Self.instant) + storage.fail(true) + #expect(throws: LedgerStorage.Failure()) { try sequencer.reserve([Self.key("b")], at: Self.instant) } + #expect(throws: LedgerStorage.Failure()) { try sequencer.release([Self.key("a")]) } + #expect(throws: LedgerStorage.Failure()) { try sequencer.producerInstance } + sequencer.releaseIgnoringErrors([Self.key("a")]) + storage.fail(false) + #expect(try sequencer.reserve([Self.key("a")], at: Self.instant).map(\.sequence.rawValue) == ["1"], "the failed release left the reservation") + sequencer.releaseIgnoringErrors([Self.key("a")]) + #expect(try sequencer.reserve([Self.key("a")], at: Self.instant).map(\.sequence.rawValue) == ["2"]) + } + + @Test("Release on an empty storage stores nothing") + func releaseOnEmptyStorageIsANoOp() throws { + let storage = LedgerStorage() + let sequencer = ExchangeEventSequencer(storage: storage) + try sequencer.release([Self.key("a")]) + sequencer.releaseIgnoringErrors([Self.key("a")]) + #expect(storage.data == nil) + #expect(storage.writes == 0) + } + + @Test("A ledger of another schema version is refused, not misread") + func unsupportedSchemaVersionIsRefused() throws { + let storage = LedgerStorage() + storage.seed(#"{"schemaVersion":99,"producerInstance":"1F5C58AA-6EC6-4E79-A682-829A9DEBD3F5","nextSequence":7,"reservations":{}}"#) + let sequencer = ExchangeEventSequencer(storage: storage) + #expect(throws: ExchangeEventSequencer.StateError.unsupportedSchemaVersion(99)) { + try sequencer.reserve([Self.key("a")], at: Self.instant) + } + #expect(throws: ExchangeEventSequencer.StateError.unsupportedSchemaVersion(99)) { try sequencer.producerInstance } + #expect(throws: ExchangeEventSequencer.StateError.unsupportedSchemaVersion(99)) { try sequencer.release([Self.key("a")]) } + #expect(storage.writes == 0) + } + + @Test("A ledger whose sequences are spent refuses a new key but still returns reserved ones") + func exhaustedSequencesAreRefused() throws { + let storage = LedgerStorage() + let reserved = Self.key("a").rawValue + storage.seed( + #"{"schemaVersion":1,"producerInstance":"1F5C58AA-6EC6-4E79-A682-829A9DEBD3F5","nextSequence":18446744073709551615,"# + + #""reservations":{"\#(reserved)":{"sequence":5,"instantMilliseconds":1791023400251,"reservedAtMilliseconds":1791023400251}}}"# + ) + let sequencer = ExchangeEventSequencer(storage: storage) + #expect(try sequencer.producerInstance == UUID(uuidString: "1F5C58AA-6EC6-4E79-A682-829A9DEBD3F5")) + #expect(try sequencer.reserve([Self.key("a")], at: Self.instant).map(\.sequence.rawValue) == ["5"]) + #expect(throws: ExchangeEventSequencer.StateError.sequencesExhausted) { + try sequencer.reserve([Self.key("a"), Self.key("b")], at: Self.instant) + } + #expect(storage.writes == 0, "a refused reservation stores nothing") + } + + @Test("The instant is kept at millisecond precision, the same the lexeme prints") + func instantIsKeptAtMillisecondPrecision() throws { + let sequencer = ExchangeEventSequencer.inMemory() + let inputs = [ + Date(timeIntervalSince1970: 1_791_023_400.2504), + Date(timeIntervalSince1970: 1_791_023_400.2506), + Date(timeIntervalSinceReferenceDate: 0.0015), + Date(timeIntervalSince1970: 1_791_023_400) + ] + let reservations = try sequencer.reserve(inputs.indices.map { Self.key("\($0)") }, at: Self.instant) + #expect(reservations.allSatisfy { ExchangeInstant.millisecondsSinceEpoch($0.instant) == 1_791_023_400_251 }) + for (index, input) in inputs.enumerated() { + let reservation = try sequencer.reserve([Self.key("input-\(index)")], at: input)[0] + #expect(ExchangeInstant.utcLexeme(reservation.instant) == ExchangeInstant.utcLexeme(input)) + #expect(ExchangeInstant.millisecondsSinceEpoch(reservation.instant) == ExchangeInstant.millisecondsSinceEpoch(input)) + #expect(reservation.instant == ExchangeInstant.date(millisecondsSinceEpoch: ExchangeInstant.millisecondsSinceEpoch(input))) + } + } + + @Test("Concurrent reservations from several tasks take unique sequences") + func concurrentReservationsAreUnique() async throws { + let sequencer = ExchangeEventSequencer.inMemory() + let tasks = 8 + let keysPerTask = 50 + let sequences = try await withThrowingTaskGroup(of: [String].self) { group in + for task in 0.. 1) let documents = [ - ExchangeGraph.ValidationDocument(bundle: graph.bundle, jsonData: graph.jsonData), + ExchangeGraph.ValidationDocument(bundle: graph.bundle, jsonData: graph.json), ExchangeGraph.ValidationDocument(bundle: graph.bundle, jsonData: nil) ] for document in documents { @@ -150,7 +150,7 @@ struct ExchangeGraphValidationDocumentTests { let converter = HealthKitConverter() let context = Self.context() let sample = Self.heartRateSample() - let stored = try converter.convert(sample, context: context).primary.graph.jsonData + let stored = try converter.convert(sample, context: context).primary.graph.json let iterations = 500 let round = { () throws -> Int in try autoreleasepool { diff --git a/Tests/GroveHealthKitFHIRTests/ExchangeInstantTests.swift b/Tests/GroveHealthKitFHIRTests/ExchangeInstantTests.swift new file mode 100644 index 000000000..179c8a454 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ExchangeInstantTests.swift @@ -0,0 +1,179 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +import Foundation +@testable import GroveFHIRContract +import ModelsR4 +import Testing + + +/// Pins the wire lexeme of a converter clock instant: UTC, millisecond precision, ASCII, no formatter. +@Suite +struct ExchangeInstantTests { + /// Instants and their lexemes, from the epoch second (and, where it matters, a fraction) in UTC. + private static let pinned: [(seconds: TimeInterval, lexeme: String)] = [ + (1_791_023_400, "2026-10-03T10:30:00Z"), + (1_791_023_400.5, "2026-10-03T10:30:00.5Z"), + (1_791_023_400.251, "2026-10-03T10:30:00.251Z"), + (1_791_023_400.25, "2026-10-03T10:30:00.25Z"), + (1_791_023_400.001, "2026-10-03T10:30:00.001Z"), + (1_791_023_400.999, "2026-10-03T10:30:00.999Z"), + (1_791_023_400.0004, "2026-10-03T10:30:00Z"), + (1_791_023_400.9996, "2026-10-03T10:30:01Z"), + (0, "1970-01-01T00:00:00Z"), + (-0.001, "1969-12-31T23:59:59.999Z"), + (978_307_200, "2001-01-01T00:00:00Z"), + (946_684_799, "1999-12-31T23:59:59Z"), + (946_684_800, "2000-01-01T00:00:00Z"), + (1_798_761_599.9996, "2027-01-01T00:00:00Z"), + (1_709_164_800, "2024-02-29T00:00:00Z"), + (951_825_600, "2000-02-29T12:00:00Z"), + (-2_203_891_200, "1900-03-01T00:00:00Z"), + (4_107_542_399, "2100-02-28T23:59:59Z"), + (4_107_542_400, "2100-03-01T00:00:00Z"), + (-12_219_724_800, "1582-10-10T00:00:00Z"), + (-62_135_596_800, "0001-01-01T00:00:00Z"), + (253_402_300_799, "9999-12-31T23:59:59Z") + ] + + @Test("Whole seconds, fractions and boundaries print as pinned", arguments: Self.pinned) + func pinnedLexemes(_ pin: (seconds: TimeInterval, lexeme: String)) { + #expect(ExchangeInstant.utcLexeme(Date(timeIntervalSince1970: pin.seconds)) == pin.lexeme) + } + + /// `Date` stores seconds since 2001, so a half-millisecond tie is exact only against that reference. + @Test("Half a millisecond rounds to the even millisecond", arguments: [ + (0.0005, "2001-01-01T00:00:00Z"), + (0.0015, "2001-01-01T00:00:00.002Z"), + (0.0025, "2001-01-01T00:00:00.002Z"), + (0.0035, "2001-01-01T00:00:00.004Z"), + (1.0005, "2001-01-01T00:00:01Z"), + (1.0015, "2001-01-01T00:00:01.002Z"), + (-0.0005, "2001-01-01T00:00:00Z"), + (-0.0015, "2000-12-31T23:59:59.998Z") + ]) + func tiesToEven(_ pin: (sinceReference: TimeInterval, lexeme: String)) { + #expect((pin.sinceReference * 1000).remainder(dividingBy: 1) == 0.5 || (pin.sinceReference * 1000).remainder(dividingBy: 1) == -0.5) + #expect(ExchangeInstant.utcLexeme(Date(timeIntervalSinceReferenceDate: pin.sinceReference)) == pin.lexeme) + } + + @Test("The binary64 neighbour below a millisecond still prints that millisecond") + func binaryNeighbourRoundsUp() { + let date = Date(timeIntervalSince1970: 1_787_009_400.251) + #expect(date.timeIntervalSince1970 < 1_787_009_400.251 || date.timeIntervalSinceReferenceDate * 1000 < 808_702_200_251) + #expect(ExchangeInstant.utcLexeme(date) == "2026-08-17T23:30:00.251Z") + } + + @Test("Whole-second instants equal what FHIRModels builds from the date in UTC", arguments: [ + 1_791_023_400, 0, 978_307_200, 946_684_799, 1_709_164_800, 4_107_542_400, 253_402_300_799 + ] as [TimeInterval]) + func matchesFHIRModelsForWholeSeconds(_ seconds: TimeInterval) throws { + let date = Date(timeIntervalSince1970: seconds) + let instant = try ExchangeInstant.fhirInstant(date) + let dateTime = try ExchangeInstant.fhirDateTime(date) + let modelsInstant = try Instant(utc: date) + let modelsDateTime = try DateTime(utc: date) + #expect(instant == modelsInstant) + #expect(instant.description == modelsInstant.description) + #expect(dateTime == modelsDateTime) + #expect(dateTime.description == modelsDateTime.description) + #expect(instant.description == ExchangeInstant.utcLexeme(date)) + #expect(dateTime.description == ExchangeInstant.utcLexeme(date)) + } + + @Test("FHIRModels keeps the parsed fraction verbatim") + func fhirTypesKeepTheLexeme() throws { + for seconds in [1_791_023_400.251, 1_791_023_400.5, 1_791_023_400.001, 1_791_023_400.25] as [TimeInterval] { + let date = Date(timeIntervalSince1970: seconds) + let lexeme = ExchangeInstant.utcLexeme(date) + #expect(try ExchangeInstant.fhirInstant(date).description == lexeme) + #expect(try ExchangeInstant.fhirDateTime(date).description == lexeme) + let instant = try ExchangeInstant.fhirInstant(date) + #expect(instant.timeZone == TimeZone(secondsFromGMT: 0)) + #expect(try Instant(lexeme) == instant) + } + } + + @Test("A year outside four digits is not a FHIR instant") + func outOfRangeYearsAreRefused() { + let tenThousand = Date(timeIntervalSince1970: 253_402_300_800) + #expect(ExchangeInstant.utcLexeme(tenThousand) == "10000-01-01T00:00:00Z") + #expect(throws: (any Error).self) { try ExchangeInstant.fhirInstant(tenThousand) } + #expect(throws: (any Error).self) { try ExchangeInstant.fhirDateTime(tenThousand) } + #expect(ExchangeInstant.utcLexeme(Date(timeIntervalSince1970: -62_135_596_801)) == "0000-12-31T23:59:59Z") + } + + @Test("Millisecond counts round-trip through the instant they name") + func millisecondCountsRoundTrip() { + var generator = SystemRandomNumberGenerator() + for _ in 0..<5000 { + let milliseconds = Int64.random(in: -62_135_596_800_000...253_402_300_799_999, using: &generator) + let date = ExchangeInstant.date(millisecondsSinceEpoch: milliseconds) + #expect(ExchangeInstant.millisecondsSinceEpoch(date) == milliseconds) + } + #expect(ExchangeInstant.millisecondsSinceEpoch(Date(timeIntervalSince1970: 1_791_023_400.251)) == 1_791_023_400_251) + let named = ExchangeInstant.date(millisecondsSinceEpoch: 1_791_023_400_251) + #expect(abs(named.timeIntervalSince1970 - 1_791_023_400.251) < 0.000_001) + #expect(ExchangeInstant.utcLexeme(named) == "2026-10-03T10:30:00.251Z") + } + + /// Foundation's calendar is proleptic Gregorian from 1582-10-15 on, so it can check the arithmetic there. + @Test("Matches Foundation's UTC calendar for millisecond instants after the Gregorian reform") + func matchesFoundationCalendar() throws { + var calendar = Calendar(identifier: .iso8601) + calendar.timeZone = try #require(TimeZone(secondsFromGMT: 0)) + var generator = SystemRandomNumberGenerator() + for _ in 0..<2000 { + let milliseconds = Int64.random(in: -12_219_292_800_000...253_402_300_799_999, using: &generator) + let date = ExchangeInstant.date(millisecondsSinceEpoch: milliseconds) + let parts = calendar.dateComponents([.year, .month, .day, .hour, .minute, .second, .nanosecond], from: date) + let millisecond = Int((Double(try #require(parts.nanosecond)) / 1_000_000).rounded()) + var fraction = millisecond == 0 ? "" : "." + String(format: "%03d", millisecond) + while fraction.hasSuffix("0") { + fraction.removeLast() + } + let expected = String( + format: "%04d-%02d-%02dT%02d:%02d:%02d", + try #require(parts.year), + try #require(parts.month), + try #require(parts.day), + try #require(parts.hour), + try #require(parts.minute), + try #require(parts.second) + ) + fraction + "Z" + #expect(ExchangeInstant.utcLexeme(date) == expected, "\(milliseconds)") + } + } + + /// The lexeme never consults a locale, so it cannot pick up a locale's digits; the test shows what + /// those digits would look like and that none of them appear, as the process locale cannot be swapped here. + @Test("Digits stay ASCII where a locale-aware formatter would not") + func digitsStayASCII() { + let formatter = NumberFormatter() + formatter.locale = Locale(identifier: "ar_EG") + let localized = formatter.string(from: 2026) ?? "" + #expect(!localized.utf8.allSatisfy { $0 < 0x80 }, "ar_EG formats digits outside ASCII; the contrast below is meaningful") + var generator = SystemRandomNumberGenerator() + for _ in 0..<2000 { + let milliseconds = Int64.random(in: -62_135_596_800_000...253_402_300_799_999, using: &generator) + let lexeme = ExchangeInstant.utcLexeme(ExchangeInstant.date(millisecondsSinceEpoch: milliseconds)) + #expect(lexeme.utf8.allSatisfy { $0 < 0x80 }) + #expect(lexeme.utf8.allSatisfy { (0x30...0x39).contains($0) || "-T:.Z".utf8.contains($0) }) + #expect(lexeme.hasSuffix("Z") && lexeme.count >= 20 && lexeme.count <= 24) + } + } + + @Test("Non-finite instants saturate instead of trapping") + func nonFiniteInstantsSaturate() { + #expect(ExchangeInstant.utcLexeme(Date(timeIntervalSince1970: .infinity)) == ExchangeInstant.utcLexeme(Date(timeIntervalSince1970: .nan))) + #expect(ExchangeInstant.utcLexeme(Date(timeIntervalSince1970: -.infinity)).hasPrefix("-")) + #expect(throws: (any Error).self) { try ExchangeInstant.fhirInstant(Date(timeIntervalSince1970: .infinity)) } + #expect(ExchangeInstant.utcLexeme(.distantFuture) == "4001-01-01T00:00:00Z") + #expect(ExchangeInstant.utcLexeme(.distantPast) == "0000-12-30T00:00:00Z") + } +} diff --git a/Tests/GroveHealthKitFHIRTests/ExchangeProducerTests.swift b/Tests/GroveHealthKitFHIRTests/ExchangeProducerTests.swift new file mode 100644 index 000000000..98f8a00ca --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ExchangeProducerTests.swift @@ -0,0 +1,213 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +import CryptoKit +import Foundation +import GroveFHIRContract +import ModelsR4 +import Testing + + +/// Pins the one-step scope of a deployment root against the two-step construction it stands for. +@Suite +struct OpaqueIdentityScopeRootTests { + private static let root: IdentifierSystem = "https://study.example.org/fhir" + private static let key = SymmetricKey(data: Data(repeating: 0x42, count: 32)) + + @Test("The root scope derives the recommended systems and mints the same identities as the two-step scope") + func rootScopeEqualsDerivedScope() throws { + let scope = try OpaqueIdentityScope(root: Self.root, keyID: "key-1", epoch: EventSequence(3), key: Self.key) + let systems = try DeploymentIdentifierSystems.derived(root: Self.root, keyID: "key-1", epoch: EventSequence(3)) + let twoStep = try OpaqueIdentityScope(systems: systems, keyID: "key-1", epoch: EventSequence(3), key: Self.key) + #expect(scope.systems == systems) + #expect(scope.keyID == "key-1") + #expect(scope.epoch == EventSequence(3)) + #expect(scope.systems.event.rawValue == "https://study.example.org/fhir/NamingSystem/grove-event-v0") + #expect(scope.systems.opaque.sourceRecord.rawValue == "https://study.example.org/fhir/NamingSystem/grove-source-record-v0/key-1/3") + let repository = try BusinessIdentifier(system: IdentifierSystem("https://study.example.org/fhir/repository"), value: "primary") + let minted = try scope.sourceRecord(adapterID: "healthkit", sourceType: "heart-rate", repositoryScope: repository, nativeRecordID: "abc") + let expected = try twoStep.sourceRecord(adapterID: "healthkit", sourceType: "heart-rate", repositoryScope: repository, nativeRecordID: "abc") + #expect(minted.identifier == expected.identifier) + #expect(minted.identifier.identifier.value.hasPrefix("v0:key-1:3:")) + #expect(minted.identifier.identifier.system == systems.opaque.sourceRecord) + #expect(scope.debugDescription == "OpaqueIdentityScope(keyID: key-1, epoch: 3)") + } + + @Test("A trailing slash on the root is dropped, as the two-step derivation drops it") + func trailingSlashIsDropped() throws { + let scope = try OpaqueIdentityScope(root: "https://study.example.org/fhir/", keyID: "key-1", epoch: EventSequence(1), key: Self.key) + #expect(scope.systems.entryNode.rawValue == "https://study.example.org/fhir/NamingSystem/grove-entry-node-v0") + } + + @Test("The root scope reports its own faults as opaque-identity errors") + func rootScopeReportsFaults() { + #expect(throws: OpaqueIdentityError.invalidKeyID("key one")) { + try OpaqueIdentityScope(root: Self.root, keyID: "key one", epoch: EventSequence(1), key: Self.key) + } + #expect(throws: OpaqueIdentityError.invalidKeyID("")) { + try OpaqueIdentityScope(root: Self.root, keyID: "", epoch: EventSequence(1), key: Self.key) + } + #expect(throws: OpaqueIdentityError.keyTooShort(actualBytes: 16)) { + try OpaqueIdentityScope(root: Self.root, keyID: "key-1", epoch: EventSequence(1), key: SymmetricKey(size: .bits128)) + } + #expect(throws: OpaqueIdentityError.publishedConformanceKeyProhibited) { + try OpaqueIdentityScope( + root: Self.root, + keyID: "key-1", + epoch: EventSequence(1), + key: SymmetricKey(data: Data((0...31).map(UInt8.init))) + ) + } + #expect(OpaqueIdentityError.invalidDeploymentRoot("x").diagnostic.code == ExchangeGraphRule.mobileInputUnclassified.rawValue) + } +} + + +@Suite +struct ExchangeProducerTests { + private static let key = SymmetricKey(data: Data(repeating: 0x42, count: 32)) + + private static func scope() throws -> OpaqueIdentityScope { + try OpaqueIdentityScope(root: "https://study.example.org/fhir", keyID: "key-1", epoch: EventSequence(1), key: key) + } + + private static func identifier(_ system: String, _ value: String) throws -> BusinessIdentifier { + try BusinessIdentifier(system: IdentifierSystem(system), value: value) + } + + private static func enrollment( + study: BusinessIdentifier? = nil, + enrollment: BusinessIdentifier? = nil, + name: String = "a" + ) throws -> StudyEnrollment { + try StudyEnrollment( + study: study ?? identifier("https://study.example.org/fhir/study", name), + protocolURL: FHIRPrimitive(Canonical(stringLiteral: "https://study.example.org/PlanDefinition/\(name)")), + protocolVersion: "1", + enrollment: enrollment ?? identifier("https://study.example.org/fhir/enrollment", "enrollment-\(name)") + ) + } + + private static func producer( + subject: Subject? = nil, + studies: [StudyEnrollment] = [], + host: HostDevice? = nil + ) throws -> ExchangeProducer { + let scope = try scope() + let subject = try subject ?? .logical(identifier("https://study.example.org/fhir/participant", "p-1")) + let application = try ApplicationDevice(name: "Grove Test", bundleIdentifier: "org.grovealliance.test", version: "1.0", build: "7") + return try ExchangeProducer( + identityScope: scope, + subject: subject, + application: application, + host: host ?? HostDevice(operatingSystemVersion: "20.1", name: "Host", manufacturer: "Example", modelNumber: "Phone1"), + studies: studies, + sequencer: .inMemory() + ) + } + + @Test("A producer keeps every input it was built from") + func producerKeepsItsInputs() throws { + let scope = try Self.scope() + let subject = Subject.logical(try Self.identifier("https://study.example.org/fhir/participant", "p-1")) + let application = try ApplicationDevice(name: "Grove Test", bundleIdentifier: "org.grovealliance.test", version: "1.0") + let host = try HostDevice(operatingSystemVersion: "20.1") + let studies = [try Self.enrollment(name: "a"), try Self.enrollment(name: "b")] + let sequencer = ExchangeEventSequencer.inMemory() + let producer = try ExchangeProducer( + identityScope: scope, + subject: subject, + application: application, + host: host, + studies: studies, + sequencer: sequencer + ) + #expect(producer.identityScope.systems == scope.systems) + #expect(producer.subject == subject) + #expect(producer.application == application) + #expect(producer.host == host) + #expect(producer.studies == studies) + #expect(producer.sequencer === sequencer) + #expect(try producer.sequencer.producerInstance == sequencer.producerInstance) + } + + @Test("The host and the studies default to the current host and no enrollment") + func defaultsDescribeThisHost() throws { + let producer = try ExchangeProducer( + identityScope: Self.scope(), + subject: .logical(Self.identifier("https://study.example.org/fhir/participant", "p-1")), + application: ApplicationDevice(name: "Grove Test", bundleIdentifier: "org.grovealliance.test", version: "1.0"), + sequencer: .inMemory() + ) + #expect(producer.host.operatingSystemVersion == HostDevice.current().operatingSystemVersion) + #expect(producer.host.sourceDeviceToken == HostDevice.current().sourceDeviceToken) + #expect(producer.studies.isEmpty) + } + + @Test("A bundled subject is accepted with its pseudonym") + func bundledSubjectIsAccepted() throws { + let pseudonym = try Self.identifier("https://study.example.org/fhir/participant", "p-1") + let producer = try Self.producer(subject: .bundled(pseudonym, Patient())) + #expect(producer.subject.identifier == pseudonym) + } + + @Test("A subject numbered in a deployment identity system is refused") + func reservedSubjectSystemIsRefused() throws { + let systems = try Self.scope().systems + for system in systems.opaque.all + [systems.event, systems.entryNode] { + let subject = Subject.logical(try BusinessIdentifier(system: system, value: "p-1")) + #expect(throws: ExchangeProducer.ConfigurationError.reservedSubjectIdentifierSystem(system)) { + try Self.producer(subject: subject) + } + #expect(throws: ExchangeProducer.ConfigurationError.reservedSubjectIdentifierSystem(system)) { + try Self.producer(subject: .bundled(BusinessIdentifier(system: system, value: "p-1"), Patient())) + } + } + } + + @Test("A study or enrollment numbered in a deployment identity system is refused") + func reservedStudySystemIsRefused() throws { + let systems = try Self.scope().systems + let reservedStudy = try BusinessIdentifier(system: systems.event, value: "study") + #expect(throws: ExchangeProducer.ConfigurationError.reservedStudyIdentifierSystem(systems.event)) { + try Self.producer(studies: [Self.enrollment(study: reservedStudy)]) + } + let reservedEnrollment = try BusinessIdentifier(system: systems.opaque.sourceRecord, value: "enrollment") + #expect(throws: ExchangeProducer.ConfigurationError.reservedStudyIdentifierSystem(systems.opaque.sourceRecord)) { + try Self.producer(studies: [Self.enrollment(name: "a"), Self.enrollment(enrollment: reservedEnrollment, name: "b")]) + } + } + + @Test("The same study or enrollment listed twice is refused") + func duplicateEnrollmentsAreRefused() throws { + let study = try Self.identifier("https://study.example.org/fhir/study", "shared") + #expect(throws: ExchangeProducer.ConfigurationError.duplicateStudy(study)) { + try Self.producer(studies: [Self.enrollment(study: study, name: "a"), Self.enrollment(study: study, name: "b")]) + } + let enrollment = try Self.identifier("https://study.example.org/fhir/enrollment", "shared") + #expect(throws: ExchangeProducer.ConfigurationError.duplicateEnrollment(enrollment)) { + try Self.producer(studies: [Self.enrollment(enrollment: enrollment, name: "a"), Self.enrollment(enrollment: enrollment, name: "b")]) + } + #expect(try Self.producer(studies: [Self.enrollment(name: "a"), Self.enrollment(name: "b")]).studies.count == 2) + } + + @Test("Every configuration fault reports the unclassified input diagnostic at the producer") + func configurationFaultsReportOneDiagnostic() throws { + let identifier = try Self.identifier("https://study.example.org/fhir/study", "s") + let faults: [ExchangeProducer.ConfigurationError] = [ + .reservedSubjectIdentifierSystem(identifier.system), + .reservedStudyIdentifierSystem(identifier.system), + .duplicateStudy(identifier), + .duplicateEnrollment(identifier) + ] + for fault in faults { + #expect(fault.diagnostic.code == ExchangeGraphRule.mobileInputUnclassified.rawValue) + #expect(fault.diagnostic.location == "ExchangeProducer") + } + } +} diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift index 3ce446977..d76946042 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift @@ -149,7 +149,7 @@ private enum TokenDiff { /// Pins the converter's current wire output, token for token, so the refactor can be proven identical. /// -/// Each case converts fixed inputs through the OLD API and compares the graph's stored JSON (`ExchangeGraph.jsonData`, +/// Each case converts fixed inputs through the OLD API and compares the graph's stored JSON (`ExchangeGraph.json`, /// the bytes a consumer uploads) with the checked-in golden over lossless tokens: member order is free, array order /// and decimal lexemes are not. A failure names the first differing path. @Suite @@ -157,7 +157,7 @@ struct GoldenGraphTests { @Test(.enabled(if: !GoldenStore.isGenerating), arguments: GoldenCase.all) func matchesCheckedInGolden(_ goldenCase: GoldenCase) throws { let output = try goldenCase.output() - let actual = try LosslessJSONValue(parsing: output.graph.jsonData) + let actual = try LosslessJSONValue(parsing: output.graph.json) let expected = try LosslessJSONValue(parsing: GoldenStore.data(named: goldenCase.name)) let outline = try #require(GoldenStore.outlines()[goldenCase.name], "no outline is pinned for \(goldenCase.name)") @@ -197,9 +197,9 @@ struct GoldenGraphTests { for goldenCase in GoldenCase.all { let output = try goldenCase.output() let graph = output.graph - let wire = try LosslessJSONValue(parsing: graph.jsonData) + let wire = try LosslessJSONValue(parsing: graph.json) let again = try goldenCase.output() - #expect(try LosslessJSONValue(parsing: again.graph.jsonData) == wire, "\(goldenCase.name) is not deterministic") + #expect(try LosslessJSONValue(parsing: again.graph.json) == wire, "\(goldenCase.name) is not deterministic") #expect(again.warnings == output.warnings, "\(goldenCase.name) does not warn deterministically") let sorted = try GoldenStore.encoder.encode(graph.bundle) #expect(try LosslessJSONValue(parsing: sorted) == wire, "\(goldenCase.name): a sorted re-encode changes the tokens") From a5e85cb020656e1d982b31cef0956fc5eb43dc54 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sat, 3 Oct 2026 13:04:47 +0200 Subject: [PATCH 004/220] Add the HealthKit FHIR Exporter A long-lived `HealthKitFHIRExporter` replaces the per-sample context plumbing of `HealthKitConverter`: it is configured once from an `ExchangeProducer`, a repository scope and `Options`, mints every event through the producer's `ExchangeEventSequencer` (so an exact redelivery before `Receipt.release()` reproduces the same bytes), converts samples, companion records (ECG, heartbeat series, workout route) and deletions in input order, and reports each outcome as a validated graph, a refusal diagnostic or `nothingToRetract` without ending the call. Options express the deployment's policies once: `WriterPolicy.automatic` classifies Apple's per-device sources (`com.apple.health.`) as the physical device that recorded the sample and every other source as an application; a `.device` writer without a stable `HKDevice` token now derives the recording Device from that source (name, `Apple Inc.`, product type) instead of omitting the author; `.omit` writers and recording devices state nothing and never warn; `legacyBundleID = .healthKitUUID` keeps the uppercase HealthKit UUID in `Bundle.id` for receivers that still key on it (deprecated at introduction). A native identifier under one of the deployment's own systems is refused at configuration. The exporter is a facade over the existing conversion code: every graph is byte-identical to the old entry point's under the same event (pinned by the goldens and the new exporter tests). The `HealthKitConverter` public entry points stay as a deprecated shim for the existing tests and consumers; their bodies moved into internal statics the exporter calls. Co-Authored-By: Claude Fable 5.1 --- .../HealthKitConverter+ClinicalDocument.swift | 2 + .../HealthKitConverter+Devices.swift | 44 ++- .../HealthKitConverter+ECG.swift | 1 + .../HealthKitConverter+GraphAssembly.swift | 5 +- ...ealthKitConverter+RecordingDocuments.swift | 71 +++-- .../HealthKitConverter+Retraction.swift | 31 +- .../HealthKitConverter.swift | 6 + .../HealthKitFHIRDisclosurePolicies.swift | 2 + .../HealthKitFHIRExporter+Options.swift | 152 ++++++++++ .../HealthKitFHIRExporter+Results.swift | 108 +++++++ .../HealthKitFHIRExporter+Retraction.swift | 101 +++++++ .../HealthKitFHIRExporter.swift | 250 ++++++++++++++++ .../HealthKitFHIRExporterTests.swift | 267 ++++++++++++++++++ 13 files changed, 999 insertions(+), 41 deletions(-) create mode 100644 Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift create mode 100644 Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift create mode 100644 Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift create mode 100644 Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift create mode 100644 Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+ClinicalDocument.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+ClinicalDocument.swift index df4ddf7f9..e803b5ce5 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+ClinicalDocument.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter+ClinicalDocument.swift @@ -24,6 +24,7 @@ extension HealthKitConverter { /// The source release is mapped from `HKFHIRVersion.fhirRelease` to the attachment's versioned /// FHIR JSON media type. Grove validates only that the bytes contain one FHIR resource envelope; /// it never converts, re-encodes, or claims conformance over the provider's resource. + @available(*, deprecated, message: "Use HealthKitFHIRExporter; removed with the exporter rework's final cleanup.") public func convert( _ record: HKClinicalRecord, context: HealthKitConversionContext @@ -97,6 +98,7 @@ extension HealthKitConverter { /// - Note: `HKCDADocumentSample.document` is populated only for a sample returned by an /// `HKDocumentQuery` that asked for document data, so a sample from any other query fails /// closed rather than converting to an empty payload. + @available(*, deprecated, message: "Use HealthKitFHIRExporter; removed with the exporter rework's final cleanup.") public func convert( _ sample: HKCDADocumentSample, context: HealthKitConversionContext diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+Devices.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+Devices.swift index 51798cc16..0de3e6efb 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+Devices.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter+Devices.swift @@ -138,26 +138,54 @@ extension HealthKitConverter { warning: .recordingDeviceOmitted(deviceName: healthKitDevice.name?.nonBlank) ) } + return try recordingDeviceSnapshot(recorder: recorder, healthKitDevice: healthKitDevice, context: context) + } + + /// The physical unit an Apple per-device source stands for, when the sample carries no `HKDevice` + /// with a stable token: the source's per-device bundle identifier is that token. Any other source + /// yields nothing, exactly as before; its manufacturer and model are not known. + static func recordingDevice( + fromSource revision: HKSourceRevision, + context: HealthKitConversionContext + ) throws -> ResolvedRecordingDevice { + let bundleIdentifier = revision.source.bundleIdentifier + guard bundleIdentifier.hasPrefix(appleDeviceSourcePrefix), + let recorder = try? RecordingDevice( + stableUnitToken: bundleIdentifier, + name: revision.source.name.nonBlank, + manufacturer: "Apple Inc.", + modelNumber: revision.productType?.nonBlank + ) else { + return ResolvedRecordingDevice(device: nil, warning: nil) + } + return try recordingDeviceSnapshot(recorder: recorder, healthKitDevice: nil, context: context) + } + + private static func recordingDeviceSnapshot( + recorder: RecordingDevice, + healthKitDevice: HKDevice?, + context: HealthKitConversionContext + ) throws -> ResolvedRecordingDevice { var device = Device() device.meta = Meta(profile: [Profile.groveRecordingDevice]) device.status = FHIRPrimitive(.active) device.id = context.repositoryID(.recordingDevice)?.primitive - if let name = recorder.name ?? healthKitDevice.name?.nonBlank { + if let name = recorder.name ?? healthKitDevice?.name?.nonBlank { device.deviceName = [DeviceDeviceName( name: name.asFHIRStringPrimitive(), type: FHIRPrimitive(.userFriendlyName) )] } - device.manufacturer = (recorder.manufacturer ?? healthKitDevice.manufacturer?.nonBlank)?.asFHIRStringPrimitive() - device.modelNumber = (recorder.modelNumber ?? healthKitDevice.model?.nonBlank)?.asFHIRStringPrimitive() + device.manufacturer = (recorder.manufacturer ?? healthKitDevice?.manufacturer?.nonBlank)?.asFHIRStringPrimitive() + device.modelNumber = (recorder.modelNumber ?? healthKitDevice?.model?.nonBlank)?.asFHIRStringPrimitive() var versions: [DeviceVersion] = [] - versions.appendVersion(healthKitDevice.hardwareVersion, code: "531974", display: "MDC_ID_PROD_SPEC_HW") - versions.appendVersion(healthKitDevice.firmwareVersion, code: "531976", display: "MDC_ID_PROD_SPEC_FW") - versions.appendVersion(healthKitDevice.softwareVersion, code: "531975", display: "MDC_ID_PROD_SPEC_SW") + versions.appendVersion(healthKitDevice?.hardwareVersion, code: "531974", display: "MDC_ID_PROD_SPEC_HW") + versions.appendVersion(healthKitDevice?.firmwareVersion, code: "531976", display: "MDC_ID_PROD_SPEC_FW") + versions.appendVersion(healthKitDevice?.softwareVersion, code: "531975", display: "MDC_ID_PROD_SPEC_SW") device.version = versions.isEmpty ? nil : versions if context.options.udiDisclosure == .authorizedUDI, - let udi = healthKitDevice.udiDeviceIdentifier?.nonBlank { + let udi = healthKitDevice?.udiDeviceIdentifier?.nonBlank { device.udiCarrier = [DeviceUdiCarrier(deviceIdentifier: udi.asFHIRStringPrimitive())] } let stableIdentity = try context.identityScope.recordingDevice( @@ -189,6 +217,8 @@ extension HealthKitConverter { // The graph envelope reuses its recording Device as the writer. A second Device keyed // from application, model, or record identifiers would falsely claim a physical unit. return nil + case .omit: + return nil } } diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+ECG.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+ECG.swift index 81d8e9863..4d9064425 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+ECG.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter+ECG.swift @@ -24,6 +24,7 @@ extension HealthKitConverter { /// ECG's event context for a symptom would collapse two source-record revisions into one /// event, while omitting symptom conversions would leave identifier-only `hasMember` /// references dangling. + @available(*, deprecated, message: "Use HealthKitFHIRExporter; removed with the exporter rework's final cleanup.") public func convert( _ record: HealthKitECGRecord, context: HealthKitConversionContext, diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+GraphAssembly.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+GraphAssembly.swift index f26081510..03491d9e5 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+GraphAssembly.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter+GraphAssembly.swift @@ -121,7 +121,10 @@ extension HealthKitConverter { context: context ) let converter = try converterSnapshots(context: context) - let recordingDevice = try Self.recordingDevice(for: sample.device, context: context) + var recordingDevice = try Self.recordingDevice(for: sample.device, context: context) + if context.options.writer == .device, recordingDevice.device == nil { + recordingDevice = try Self.recordingDevice(fromSource: sample.sourceRevision, context: context) + } let writer = try Self.writer( for: sample.sourceRevision, classification: context.options.writer, diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+RecordingDocuments.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+RecordingDocuments.swift index 351073363..d7ee2cfb4 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+RecordingDocuments.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter+RecordingDocuments.swift @@ -86,60 +86,73 @@ extension HealthKitConverter { /// ```swift /// let conversion = try HealthKitConverter().convert(record, context: context) /// ``` + @available(*, deprecated, message: "Use HealthKitFHIRExporter; removed with the exporter rework's final cleanup.") public func convert( _ record: HealthKitHeartbeatSeriesRecord, context: HealthKitConversionContext ) throws(HealthKitConversionError) -> HealthKitConversionSet { do { - return try Self.assembleDocumentGraph( - for: record.series, - evidence: HealthKitRecordingEvidence( - outputRole: "native-recording", - format: .beatIntervalSeries, - title: "Heartbeat series beat intervals", - payload: try Self.beatIntervalPayload( - seriesStart: record.series.startDate, - heartbeats: record.heartbeats - ) - ), - context: context - ) + return try Self.convertHeartbeatSeries(record, context: context) } catch { throw HealthKitConversionError(conversionFailure: error, source: .heartbeatSeries) } } + static func convertHeartbeatSeries( + _ record: HealthKitHeartbeatSeriesRecord, + context: HealthKitConversionContext + ) throws -> HealthKitConversionSet { + try assembleDocumentGraph( + for: record.series, + evidence: HealthKitRecordingEvidence( + outputRole: "native-recording", + format: .beatIntervalSeries, + title: "Heartbeat series beat intervals", + payload: try beatIntervalPayload( + seriesStart: record.series.startDate, + heartbeats: record.heartbeats + ) + ), + context: context + ) + } + /// Converts a workout route into the recording document that carries its track. /// /// - Returns: The route's graph, or `nil` under `RouteDisclosurePolicy.omit`, the default. /// Omitting the route drops an addition rather than rejecting anything: the workout the /// route belongs to converts on its own. + @available(*, deprecated, message: "Use HealthKitFHIRExporter; removed with the exporter rework's final cleanup.") public func convert( _ record: HealthKitWorkoutRouteRecord, context: HealthKitConversionContext ) throws(HealthKitConversionError) -> HealthKitConversionSet? { do { - guard let payload = try Self.locationTrackPayload( - record.locations, - context: context - ) else { - return nil - } - return try Self.assembleDocumentGraph( - for: record.route, - evidence: HealthKitRecordingEvidence( - outputRole: "native-recording", - format: .locationTrackSamples, - title: "Workout route locations", - payload: payload - ), - context: context - ) + return try Self.convertWorkoutRoute(record, context: context) } catch { throw HealthKitConversionError(conversionFailure: error, source: .workoutRoute) } } + static func convertWorkoutRoute( + _ record: HealthKitWorkoutRouteRecord, + context: HealthKitConversionContext + ) throws -> HealthKitConversionSet? { + guard let payload = try locationTrackPayload(record.locations, context: context) else { + return nil + } + return try assembleDocumentGraph( + for: record.route, + evidence: HealthKitRecordingEvidence( + outputRole: "native-recording", + format: .locationTrackSamples, + title: "Workout route locations", + payload: payload + ), + context: context + ) + } + static func beatIntervalPayload( seriesStart: Date, heartbeats: [HealthKitHeartbeat] diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+Retraction.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+Retraction.swift index 8493df51f..4813fcf24 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+Retraction.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter+Retraction.swift @@ -41,7 +41,7 @@ extension HealthKitConverter { /// repository scope and native-identifier disclosure as the record's conversion. The source /// record and every target are recomputed from `record`, so nothing from that conversion needs /// to be kept. - public func retraction( + static func retraction( for record: HealthKitSourceRecord, context: HealthKitConversionContext, occurred: RetractionOccurrence @@ -66,17 +66,17 @@ extension HealthKitConverter { /// type: the same identity scope and the same output roles yield the same identifiers. The /// sample's UUID rides along as each target's native record identifier exactly when the /// context's native-identifier disclosure authorizes it on the addition path. - public func retractionTargets( + static func retractionTargets( for record: HealthKitSourceRecord, context: HealthKitConversionContext ) throws(HealthKitConversionError) -> [RetractionTarget] { - try Self.validate(context: context) + try validate(context: context) let outputs = HealthKitCatalog.outputs(for: record.type) guard !outputs.isEmpty else { throw Self.unconvertibleSampleError(for: record.type) } let nativeRecordIdentifier = context.options.nativeIdentifierDisclosure.nativeRecordIdentifier( - for: Self.nativeRecordID(of: record) + for: nativeRecordID(of: record) ) let sourceRecord = try Self.sourceRecord(for: record, context: context) var targets: [RetractionTarget] = [] @@ -103,6 +103,29 @@ extension HealthKitConverter { } +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitConverter { + /// The complete retraction of a deleted record, as its own exchange event. + @available(*, deprecated, message: "Use HealthKitFHIRExporter.retract; removed with the exporter rework's final cleanup.") + public func retraction( + for record: HealthKitSourceRecord, + context: HealthKitConversionContext, + occurred: RetractionOccurrence + ) throws(HealthKitConversionError) -> RetractionEvent { + try Self.retraction(for: record, context: context, occurred: occurred) + } + + /// The logical targets a deletion retracts, named from the catalog alone. + @available(*, deprecated, message: "Use HealthKitFHIRExporter.retract; removed with the exporter rework's final cleanup.") + public func retractionTargets( + for record: HealthKitSourceRecord, + context: HealthKitConversionContext + ) throws(HealthKitConversionError) -> [RetractionTarget] { + try Self.retractionTargets(for: record, context: context) + } +} + + extension HealthKitSourceType { /// The inventory row of a sample type, such as the one a deletion was reported for. public init?(_ sampleType: HKSampleType) { diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter.swift index 362c622fc..852a5364c 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter.swift @@ -21,9 +21,11 @@ import ModelsR4 /// authorize data access, synchronize anchors, persist resources, or upload anything. @available(iOS 18, macOS 15, watchOS 11, *) public struct HealthKitConverter: Sendable { + @available(*, deprecated, message: "Use HealthKitFHIRExporter; removed with the exporter rework's final cleanup.") public init() {} /// Converts one sample only when the closed catalog admits its exact published contract. + @available(*, deprecated, message: "Use HealthKitFHIRExporter; removed with the exporter rework's final cleanup.") public func convert( _ sample: HKSample, context: HealthKitConversionContext @@ -39,6 +41,7 @@ public struct HealthKitConverter: Sendable { /// /// A record whose context the caller could not supply fails with the caller's own error and /// never becomes a conversion refusal. + @available(*, deprecated, message: "Use HealthKitFHIRExporter; removed with the exporter rework's final cleanup.") public func convert( _ samples: some Sequence, context: (HKSample) throws(E) -> HealthKitConversionContext @@ -73,6 +76,9 @@ public struct HealthKitConverter: Sendable { extension HealthKitConverter { /// The closed adapter token every HealthKit identity preimage carries. static let adapterID = "healthkit" + /// The bundle-identifier prefix of HealthKit's per-device sources: the watch or phone that recorded a + /// sample itself, as `com.apple.health.`. + static let appleDeviceSourcePrefix = "com.apple.health." static func convertSample( _ sample: HKSample, diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRDisclosurePolicies.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRDisclosurePolicies.swift index 4f2eb235d..f6a01482b 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRDisclosurePolicies.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRDisclosurePolicies.swift @@ -37,6 +37,8 @@ public enum HealthKitWriter: Hashable, Sendable { /// evidence exists. Without that evidence, the Device author is omitted rather than inferred /// from model, product, application, or record identifiers. case device + /// The caller has not classified the source; no writer is stated and the Provenance names no author. + case omit } #endif diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift new file mode 100644 index 000000000..76dc56e3b --- /dev/null +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift @@ -0,0 +1,152 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +public import Foundation +public import GroveFHIRContract +public import HealthKit + + +/// The resolver behind ``HealthKitFHIRExporter/RecordingDevicePolicy/omit``. +@available(iOS 18, macOS 15, watchOS 11, *) +private struct OmittingRecordingDeviceResolver: RecordingDeviceResolver { + func recordingDevice(for device: HKDevice) -> RecordingDevice? { + nil + } +} + + +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitFHIRExporter { + /// The HealthKit-specific choices of one exporter: how sources, devices and identifiers are stated, + /// and which disclosures the deployment authorizes. Every disclosure defaults to omission. + public struct Options: Sendable { + /// How the source that wrote a sample is stated. See ``WriterPolicy``. + public var writer: WriterPolicy = .automatic + /// How the physical unit behind a sample's `HKDevice` is identified. See ``RecordingDevicePolicy``. + public var recordingDevice: RecordingDevicePolicy = .localIdentifier + /// How the converting application relates to each measurement. See ``RolePolicy``. + public var role: RolePolicy = .assembler + /// The only way the clear HealthKit UUID reaches the wire: as an identifier under a system the + /// deployment owns, on the primary output and on retraction targets. + public var nativeIdentifier: GovernedSourceIdentifierDisclosurePolicy = .omit + /// Whether a recording Device carries the UDI HealthKit supplies. + public var udi: Disclosure = .omit + /// Whether a workout route becomes a recording document; a route re-identifies readily. + public var route: Disclosure = .omit + /// A deployment that still keys its receiver on `Bundle.id` can keep the old value there for the + /// transition. See ``LegacyBundleID``. + public var legacyBundleID: LegacyBundleID = .none + + public init() {} + } + + /// How `HKSourceRevision.source`, the app or device that wrote a sample into HealthKit, is stated. + /// + /// The origin of a sample is always kept: an application becomes an application Device snapshot with + /// its bundle identifier and version plus the host it ran on; a physical device becomes a recording + /// Device with a stable, pseudonymous identity. The two shapes differ, so the exporter needs to know + /// which one a source is. + public enum WriterPolicy: Hashable, Sendable { + /// Apple's per-device sources (bundle identifiers `com.apple.health.`, i.e. a watch or + /// phone that recorded the sample itself) are physical devices; every other source is an application. + case automatic + /// Every source is stated as an application. + case application + /// Every source stands for the sample's physical device; the Provenance author is the recording Device. + case device + /// No writer is stated and the Provenance names no author. + case omit + + /// The classification of one source under this policy. + func classification(of source: HKSource) -> HealthKitWriter { + switch self { + case .automatic: + source.bundleIdentifier.hasPrefix(HealthKitConverter.appleDeviceSourcePrefix) ? .device : .application + case .application: + .application + case .device: + .device + case .omit: + .omit + } + } + } + + /// How a sample's `HKDevice` resolves to one physical unit. + public enum RecordingDevicePolicy: Sendable { + /// Use HealthKit's per-unit `HKDevice.localIdentifier`; a device without one yields no recording + /// Device and the export reports ``HealthKitConversionWarning/recordingDeviceOmitted(deviceName:)``. + case localIdentifier + /// Never emit a recording Device from `HKDevice`. + case omit + /// The deployment's own resolver. + case custom(any RecordingDeviceResolver) + + var resolver: any RecordingDeviceResolver { + switch self { + case .localIdentifier: + HealthKitLocalIdentifierResolver() + case .omit: + OmittingRecordingDeviceResolver() + case .custom(let resolver): + resolver + } + } + } + + /// How the converting application relates to the measurements it converts. + public enum RolePolicy: Hashable, Sendable { + /// The application assembled graphs from records it did not mediate. + case assembler + /// Samples this application wrote itself (the source bundle identifier equals the application's) + /// are stated as mediated by it; every other sample is merely assembled. + case gatewayForOwnWrites + /// The converting application mediated every measurement. + case gateway + /// A distinct application mediated every measurement; it travels as a second application snapshot. + case gatewayApplication(ApplicationDevice) + + /// The role for one sample under this policy. + func converterRole(for source: HKSource, application: ApplicationDevice) -> ConverterRole { + switch self { + case .assembler: + .assembler + case .gatewayForOwnWrites: + source.bundleIdentifier == application.bundleIdentifier ? .gateway : .assembler + case .gateway: + .gateway + case .gatewayApplication(let gateway): + .gatewayApplication(gateway) + } + } + } + + /// An explicit, caller-attested disclosure of information that identifies more readily than the + /// measurement itself. + public enum Disclosure: Hashable, Sendable { + case omit + case authorized + } + + /// What `Bundle.id` carries. + /// + /// The implementation guide forbids a source-native value as a resource id; receivers key on the + /// identifiers inside the Bundle instead. The HealthKit UUID stays available only for deployments + /// whose receiver has not moved yet. + public enum LegacyBundleID: Hashable, Sendable { + /// No `Bundle.id`. + case none + /// The uppercase HealthKit UUID, exactly as the earlier MyHeartCounts integration emitted it. + @available(*, deprecated, message: "Transitional: violates the guide's Resource.id rule; key the receiver on identifiers instead.") + case healthKitUUID + } +} + +#endif diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift new file mode 100644 index 000000000..37614bde1 --- /dev/null +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift @@ -0,0 +1,108 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +public import CoreLocation +public import Foundation +public import GroveFHIRContract +public import HealthKit + + +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitFHIRExporter { + /// One input of ``export(records:at:receive:)``: a sample, plus the companion data HealthKit keeps + /// outside the sample for the kinds that need it. The exporter never queries HealthKit itself. + public enum Record: Sendable { + /// Any sample; an `HKElectrocardiogram` passed here is refused because its voltages are missing. + case sample(HKSample) + /// An electrocardiogram with its voltages and correlated symptom samples; each symptom becomes an + /// event of its own. + case electrocardiogram(HKElectrocardiogram, voltages: [HKElectrocardiogram.VoltageMeasurement], symptoms: [HKCategorySample]) + /// A heartbeat series with its beats, exported as a recording document. + case heartbeatSeries(HKHeartbeatSeriesSample, beats: [HealthKitHeartbeat]) + /// A workout route with its locations, exported as a recording document only under + /// ``Options/route`` `.authorized`. + case workoutRoute(HKWorkoutRoute, locations: [CLLocation]) + + var sample: HKSample { + switch self { + case .sample(let sample): sample + case .electrocardiogram(let ecg, _, _): ecg + case .heartbeatSeries(let series, _): series + case .workoutRoute(let route, _): route + } + } + } + + /// A deleted HealthKit object as the app noted it: HealthKit reports no deletion time, so the + /// retraction states the bounds the app knows. + public struct Deletion: Hashable, Sendable { + public let uuid: UUID + public let sourceType: HealthKitSourceType + /// The start of the query that first reported the deletion, when known. + public let deletedAfter: Date? + /// When the app received the deletion. + public let detectedAt: Date + + public init(uuid: UUID, sourceType: HealthKitSourceType, deletedAfter: Date?, detectedAt: Date) { + self.uuid = uuid + self.sourceType = sourceType + self.deletedAfter = deletedAfter + self.detectedAt = detectedAt + } + } + + /// What one record produced: an exchange graph, or the reason it produced none. + public struct Export: Sendable { + /// The record's coordinate in the HealthKit store. It stays on the device and is never on the wire + /// unless ``Options/nativeIdentifier`` discloses it. + public struct Source: Hashable, Sendable { + public let uuid: UUID + /// The HealthKit type identifier, such as `HKQuantityTypeIdentifierHeartRate`. + public let typeIdentifier: String + + public var sourceType: HealthKitSourceType? { HealthKitSourceType(rawValue: typeIdentifier) } + } + + public enum Outcome: Sendable { + /// The validated graph; store or upload ``ExchangeGraph/json`` verbatim. + case graph(ExchangeGraph) + /// The record was refused with a registered diagnostic; nothing was emitted and the export continued. + case refused(ProducerDiagnostic) + /// A deletion of a source type that never emits outputs. + case nothingToRetract + } + + public let source: Source + public let outcome: Outcome + /// What the record carried that its graph does not; each is a registered omission rule. + public let warnings: [ProducerDiagnostic] + + /// The graph, when one was produced. + public var graph: ExchangeGraph? { + if case .graph(let graph) = outcome { graph } else { nil } + } + } + + /// What an export call reserved. Call ``release()`` once every produced graph is durably stored AND + /// the source cursor (HealthKit anchor, bulk-export checkpoint) is committed; until then an exact + /// redelivery of the same records reproduces the same events. + public struct Receipt: Sendable { + let keys: [ExchangeEventKey] + let sequencer: ExchangeEventSequencer + + /// Forgets the reservations. Idempotent; storage failures are swallowed because a late release only + /// means a later redelivery becomes a new event. + public func release() { + sequencer.releaseIgnoringErrors(keys) + } + } +} + +#endif diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift new file mode 100644 index 000000000..a9df4c586 --- /dev/null +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift @@ -0,0 +1,101 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +public import Foundation +import GroveFHIRContract +import HealthKit + + +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitFHIRExporter { + /// Retracts deleted records in input order, one retraction event per deletion whose source type + /// ever emits outputs. Targets are recomputed from the catalog, so nothing from the original + /// export needs to be kept. Errors from the sequencer's storage and from `receive` end the call. + public func retract( + _ deletions: some Collection, + at instant: Date = .now, + receive: (Export) throws -> Void + ) throws -> Receipt { + let retractable = deletions.filter { !HealthKitCatalog.outputs(for: $0.sourceType).isEmpty } + let keys = retractable.map(ExchangeEventKey.retraction) + let reservations = try producer.sequencer.reserve(keys, at: instant) + let producerInstance = try producer.sequencer.producerInstance + for deletion in deletions where HealthKitCatalog.outputs(for: deletion.sourceType).isEmpty { + try receive(Export(source: deletion.source, outcome: .nothingToRetract, warnings: [])) + } + for (deletion, reservation) in zip(retractable, reservations) { + let outcome: Export.Outcome + do { + outcome = .graph(try retraction(of: deletion, reservation: reservation, producerInstance: producerInstance)) + } catch { + producer.sequencer.releaseIgnoringErrors([ExchangeEventKey.retraction(deletion)]) + outcome = .refused(HealthKitConversionError(conversionFailure: error, source: deletion.sourceType).diagnostic) + } + try receive(Export(source: deletion.source, outcome: outcome, warnings: [])) + } + return Receipt(keys: keys, sequencer: producer.sequencer) + } + + private func retraction( + of deletion: Deletion, + reservation: ExchangeEventReservation, + producerInstance: UUID + ) throws -> ExchangeGraph { + let event = ExchangeEventContext( + subject: producer.subject, + event: try ExchangeEventIdentifier( + system: producer.identityScope.systems.event, + producerInstance: producerInstance, + sequence: reservation.sequence + ), + identityScope: producer.identityScope, + repositoryScope: repositoryScope, + application: producer.application, + host: producer.host, + conversionInstant: reservation.instant, + converterRole: .assembler, + studies: producer.studies, + repositoryIDs: [:] + ) + let context = HealthKitConversionContext( + event: event, + options: HealthKitConversionOptions(nativeIdentifierDisclosure: options.nativeIdentifier) + ) + let record = HealthKitSourceRecord(uuid: deletion.uuid, type: deletion.sourceType) + let occurred = RetractionOccurrence.period( + start: deletion.deletedAfter.map { min($0, deletion.detectedAt) }, + end: deletion.detectedAt + ) + return try HealthKitConverter.retraction(for: record, context: context, occurred: occurred).graph + } +} + + +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitFHIRExporter.Deletion { + var source: HealthKitFHIRExporter.Export.Source { + HealthKitFHIRExporter.Export.Source(uuid: uuid, typeIdentifier: sourceType.rawValue) + } +} + + +@available(iOS 18, macOS 15, watchOS 11, *) +extension ExchangeEventKey { + /// The retraction-event key of a deletion: the source type and UUID under the retraction kind. + static func retraction(_ deletion: HealthKitFHIRExporter.Deletion) -> ExchangeEventKey { + ExchangeEventKey( + kind: .retraction, + adapterID: HealthKitConverter.adapterID, + sourceRecord: "\(deletion.sourceType.rawValue)|\(deletion.uuid.uuidString.lowercased())" + ) + } +} + +#endif diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift new file mode 100644 index 000000000..ac6e6160f --- /dev/null +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift @@ -0,0 +1,250 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +public import Foundation +public import GroveFHIRContract +public import HealthKit + + +/// Turns HealthKit samples into exchange graphs for one deployment, participant and installation. +/// +/// Configure it once and keep it for as long as its ``ExchangeProducer`` is valid; it is safe to share +/// across tasks. Every export mints the events itself through the producer's sequencer, so an exact +/// redelivery before ``Receipt/release()`` reproduces the same events, and a sample that cannot be +/// converted is reported as a refusal instead of ending the call. The exporter never queries HealthKit: +/// companion data such as ECG voltages arrives through ``Record``. +@available(iOS 18, macOS 15, watchOS 11, *) +public final class HealthKitFHIRExporter: Sendable { + /// Why an exporter could not be configured. + public enum ConfigurationError: Error, Equatable, Sendable { + /// The disclosed native identifier's system is one of the deployment's own identity systems. + case reservedNativeIdentifierSystem(IdentifierSystem) + } + + public let producer: ExchangeProducer + /// The business identifier naming this installation's HealthKit store; it enters every source identity. + public let repositoryScope: BusinessIdentifier + public let options: Options + + public init( + producer: ExchangeProducer, + repositoryScope: BusinessIdentifier, + options: Options = Options() + ) throws(ConfigurationError) { + if case .authorized(let system, _) = options.nativeIdentifier, + producer.identityScope.systems.all.contains(system) { + throw .reservedNativeIdentifierSystem(system) + } + self.producer = producer + self.repositoryScope = repositoryScope + self.options = options + } + + /// Converts samples in input order, calling `receive` once per produced graph or refusal as soon as + /// it is ready. Only the sequencer's storage and `receive` itself can end the call early; their + /// errors are rethrown unchanged. + public func export( + _ samples: Samples, + at instant: Date = .now, + receive: (Export) throws -> Void + ) throws -> Receipt where Samples.Element: HKSample { + try export(records: samples.map { Record.sample($0) }, at: instant, receive: receive) + } + + /// ``export(_:at:receive:)`` for records that carry companion data. + public func export( + records: some Collection, + at instant: Date = .now, + receive: (Export) throws -> Void + ) throws -> Receipt { + let plans = records.map(Plan.init) + let keys = plans.flatMap(\.keys) + let reservations = try producer.sequencer.reserve(keys, at: instant) + let producerInstance = try producer.sequencer.producerInstance + var offset = 0 + for plan in plans { + let reserved = Array(reservations[offset..<(offset + plan.keys.count)]) + offset += plan.keys.count + try autoreleasepool { + try deliver(plan, reservations: reserved, producerInstance: producerInstance, receive: receive) + } + } + return Receipt(keys: keys, sequencer: producer.sequencer) + } +} + + +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitFHIRExporter { + /// One record and the event keys it needs: one for itself, one per ECG symptom. + struct Plan { + let record: Record + let keys: [ExchangeEventKey] + let refusal: ProducerDiagnostic? + + var source: Export.Source { + Export.Source(uuid: record.sample.uuid, typeIdentifier: record.sample.sampleType.identifier) + } + } + + private func deliver( + _ plan: Plan, + reservations: [ExchangeEventReservation], + producerInstance: UUID, + receive: (Export) throws -> Void + ) throws { + if let refusal = plan.refusal { + try receive(Export(source: plan.source, outcome: .refused(refusal), warnings: [])) + return + } + let set: HealthKitConversionSet? + do { + set = try convert(plan.record, reservations: reservations, producerInstance: producerInstance) + } catch { + let failure = HealthKitConversionError(conversionFailure: error, source: plan.source.sourceType) + producer.sequencer.releaseIgnoringErrors(plan.keys) + try receive(Export(source: plan.source, outcome: .refused(failure.diagnostic), warnings: [])) + return + } + guard let set else { + // A policy chose to emit nothing (an unauthorized route); that is not a refusal and never warns. + producer.sequencer.releaseIgnoringErrors(plan.keys) + return + } + for conversion in set.all { + try receive(Export( + source: Export.Source(uuid: conversion.source.uuid, typeIdentifier: conversion.source.type.rawValue), + outcome: .graph(conversion.graph), + warnings: reportableWarnings(conversion.warnings) + )) + } + } + + private func convert( + _ record: Record, + reservations: [ExchangeEventReservation], + producerInstance: UUID + ) throws -> HealthKitConversionSet? { + let context = try conversionContext(for: record.sample, reservation: reservations[0], producerInstance: producerInstance) + switch record { + case .sample(let sample): + return try HealthKitConverter.convertSample(sample, context: context) + case let .electrocardiogram(ecg, voltages, symptoms): + let symptomContexts = try zip(symptoms, reservations.dropFirst()).map { symptom, reservation in + try conversionContext(for: symptom, reservation: reservation, producerInstance: producerInstance) + } + let ecgRecord = HealthKitECGRecord(electrocardiogram: ecg, voltageMeasurements: voltages, correlatedSymptoms: symptoms) + return try HealthKitConverter.convertECG(ecgRecord, context: context, symptomContexts: symptomContexts) + case let .heartbeatSeries(series, beats): + return try HealthKitConverter.convertHeartbeatSeries( + HealthKitHeartbeatSeriesRecord(series: series, heartbeats: beats), + context: context + ) + case let .workoutRoute(route, locations): + return try HealthKitConverter.convertWorkoutRoute( + HealthKitWorkoutRouteRecord(route: route, locations: locations), + context: context + ) + } + } + + /// An omission a policy chose is never reported. + private func reportableWarnings(_ warnings: [HealthKitConversionWarning]) -> [ProducerDiagnostic] { + warnings.compactMap { warning in + if case .recordingDeviceOmitted = warning, case .omit = options.recordingDevice { + return nil + } + return warning.diagnostic + } + } +} + + +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitFHIRExporter.Plan { + init(_ record: HealthKitFHIRExporter.Record) { + self.record = record + var keys: [ExchangeEventKey] = [] + if let key = ExchangeEventKey.active(record.sample) { + keys.append(key) + } + if case .electrocardiogram(_, _, let symptoms) = record { + keys += symptoms.compactMap(ExchangeEventKey.active) + } + self.keys = keys + self.refusal = keys.isEmpty + ? HealthKitConversionError.unregisteredSourceType(record.sample.sampleType.identifier).diagnostic + : nil + } +} + + +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitFHIRExporter { + /// The per-event conversion inputs, in the shape the conversion pipeline still takes. + func conversionContext( + for sample: HKSample, + reservation: ExchangeEventReservation, + producerInstance: UUID + ) throws -> HealthKitConversionContext { + let source = sample.sourceRevision.source + let event = ExchangeEventContext( + subject: producer.subject, + event: try ExchangeEventIdentifier( + system: producer.identityScope.systems.event, + producerInstance: producerInstance, + sequence: reservation.sequence + ), + identityScope: producer.identityScope, + repositoryScope: repositoryScope, + application: producer.application, + host: producer.host, + conversionInstant: reservation.instant, + converterRole: options.role.converterRole(for: source, application: producer.application), + studies: producer.studies, + repositoryIDs: try legacyRepositoryIDs(for: sample.uuid) + ) + let conversionOptions = HealthKitConversionOptions( + writer: options.writer.classification(of: source), + recordingDevice: options.recordingDevice.resolver, + udiDisclosure: options.udi == .authorized ? .authorizedUDI : .omit, + routeDisclosure: options.route == .authorized ? .authorized : .omit, + nativeIdentifierDisclosure: options.nativeIdentifier + ) + return HealthKitConversionContext(event: event, options: conversionOptions) + } + + func legacyRepositoryIDs(for uuid: UUID) throws -> [ExchangeGraphNode: RepositoryID] { + switch options.legacyBundleID { + case .none: + [:] + default: + [.bundle: try RepositoryID(uuid.uuidString)] + } + } +} + + +@available(iOS 18, macOS 15, watchOS 11, *) +extension ExchangeEventKey { + /// The active-event key of a HealthKit sample: its source type and UUID, nothing else. + static func active(_ sample: HKSample) -> ExchangeEventKey? { + guard let type = HealthKitSourceType(sample) else { + return nil + } + return ExchangeEventKey( + kind: .active, + adapterID: HealthKitConverter.adapterID, + sourceRecord: "\(type.rawValue)|\(sample.uuid.uuidString.lowercased())" + ) + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift new file mode 100644 index 000000000..7262a5057 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift @@ -0,0 +1,267 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit +import ModelsR4 +import Testing + + +/// The exporter is a facade over the conversion the goldens pin: its graphs are byte-identical to the old +/// entry point's under the same event, and it adds the event bookkeeping and policies the entry point left +/// to the caller. +@Suite(.serialized) +struct HealthKitFHIRExporterTests { + private static let base = ExchangeEventContext.test() + + private static func exporter( + _ configure: (inout HealthKitFHIRExporter.Options) -> Void = { _ in }, + sequencer: ExchangeEventSequencer = .inMemory() + ) throws -> HealthKitFHIRExporter { + let producer = try ExchangeProducer( + identityScope: base.identityScope, + subject: base.subject, + application: base.application, + host: base.host, + sequencer: sequencer + ) + var options = HealthKitFHIRExporter.Options() + configure(&options) + return try HealthKitFHIRExporter(producer: producer, repositoryScope: base.repositoryScope, options: options) + } + + /// The old entry point's graph for `sample` under the exporter's own producer instance and `sequence`. + private static func reference( + _ sample: HKSample, + exporter: HealthKitFHIRExporter, + sequence: UInt64, + instant: Date, + _ configure: (inout HealthKitConversionOptions) -> Void = { _ in } + ) throws -> HealthKitConversion { + var options = HealthKitConversionOptions() + configure(&options) + let context = HealthKitConversionContext( + event: ExchangeEventContext( + subject: base.subject, + event: try ExchangeEventIdentifier( + system: base.identityScope.systems.event, + producerInstance: try exporter.producer.sequencer.producerInstance, + sequence: EventSequence(sequence) + ), + identityScope: base.identityScope, + repositoryScope: base.repositoryScope, + application: base.application, + host: base.host, + conversionInstant: instant + ), + options: options + ) + return try HealthKitConverter.convertSample(sample, context: context).primary + } + + private static func collect( + _ exporter: HealthKitFHIRExporter, + _ samples: [HKSample], + at instant: Date = GoldenFixtures.conversionInstant + ) throws -> (exports: [HealthKitFHIRExporter.Export], receipt: HealthKitFHIRExporter.Receipt) { + var exports: [HealthKitFHIRExporter.Export] = [] + let receipt = try exporter.export(samples, at: instant) { exports.append($0) } + return (exports, receipt) + } + + @Test("Graphs equal the old entry point's under the same event, with the same warnings") + func graphsEqualReference() throws { + let exporter = try Self.exporter() + let withDevice = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(1), device: GoldenFixtures.watch, writer: GoldenFixtures.foreignWriter) + let withoutToken = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(2), device: GoldenFixtures.watchWithoutUnitToken) + let (exports, _) = try Self.collect(exporter, [withDevice, withoutToken]) + try #require(exports.count == 2) + let instant = GoldenFixtures.conversionInstant + let first = try Self.reference(withDevice, exporter: exporter, sequence: 1, instant: instant) + let second = try Self.reference(withoutToken, exporter: exporter, sequence: 2, instant: instant) + #expect(exports[0].graph?.json == first.graph.json) + #expect(exports[1].graph?.json == second.graph.json) + #expect(exports[0].source == HealthKitFHIRExporter.Export.Source(uuid: GoldenFixtures.uuid(1), typeIdentifier: HKQuantityTypeIdentifier.heartRate.rawValue)) + #expect(exports[0].source.sourceType == .heartRate) + #expect(exports[0].warnings.isEmpty) + #expect(exports[1].warnings == second.warnings.map(\.diagnostic)) + #expect(exports[1].warnings.contains(ExchangeGraphRule.mobileOmissionRecordingDevice.diagnostic)) + #expect(exports[0].graph?.event.value == "e0:\(try exporter.producer.sequencer.producerInstance.uuidString.lowercased()):1") + #expect(exports[1].graph?.event.value.hasSuffix(":2") == true) + } + + @Test("A redelivery before release reproduces the same bytes; after release it is a new event") + func redeliveryReproducesEvents() throws { + let exporter = try Self.exporter() + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(3)) + let (first, receipt) = try Self.collect(exporter, [sample]) + let (again, _) = try Self.collect(exporter, [sample], at: GoldenFixtures.conversionInstant.addingTimeInterval(3_600)) + #expect(first[0].graph?.json == again[0].graph?.json) + receipt.release() + let (afterRelease, _) = try Self.collect(exporter, [sample]) + #expect(afterRelease[0].graph?.event.value.hasSuffix(":2") == true) + #expect(afterRelease[0].graph?.json != first[0].graph?.json) + } + + @Test("An unconvertible record is refused in place, releases its reservation, and the export continues") + func refusalsDoNotEndTheExport() throws { + let exporter = try Self.exporter() + let ecg = try StoredSampleFixtures.seriesSample( + HKElectrocardiogram.self, + sampleType: HKObjectType.electrocardiogramType(), + shape: GoldenCase.seriesShape(uuid: 4, duration: 30) + ) + let heartRate = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(5)) + let (exports, _) = try Self.collect(exporter, [ecg, heartRate]) + try #require(exports.count == 2) + guard case .refused(let diagnostic) = exports[0].outcome else { + Issue.record("expected a refusal, got \(exports[0].outcome)") + return + } + #expect(diagnostic == HealthKitConversionError.ecgEvidence(.evidenceRequired).diagnostic) + #expect(exports[0].graph == nil) + #expect(exports[1].graph?.event.value.hasSuffix(":2") == true) + // The refused ECG's reservation was released, so the next export of it takes a fresh sequence. + let (retry, _) = try Self.collect(exporter, [ecg]) + guard case .refused = retry[0].outcome else { + Issue.record("expected a refusal") + return + } + let (next, _) = try Self.collect(exporter, [try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(6))]) + #expect(next[0].graph?.event.value.hasSuffix(":4") == true) + } + + @Test("Under the automatic writer policy an Apple per-device source is the recording Device that authored the sample") + func automaticWriterClassifiesAppleDeviceSources() throws { + let exporter = try Self.exporter() + let watchSource = StoredSampleFixtures.Writer( + name: "Lukas's Apple Watch", + bundleIdentifier: "com.apple.health.6C4B1D1E-0000-4000-8000-000000000009", + version: "26.1", + productType: "Watch7,12" + ) + let fromWatch = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(7), writer: watchSource) + let fromApp = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(8), writer: GoldenFixtures.foreignWriter) + let (exports, _) = try Self.collect(exporter, [fromWatch, fromApp]) + let watchBundle = try #require(exports[0].graph?.bundle) + let devices = watchBundle.entry?.compactMap { $0.resource?.get(if: Device.self) } ?? [] + let recorder = try #require(devices.first { $0.manufacturer?.value?.string == "Apple Inc." }) + #expect(recorder.deviceName?.first?.name.value?.string == "Lukas's Apple Watch") + #expect(recorder.modelNumber?.value?.string == "Watch7,12") + #expect(recorder.meta?.profile?.contains(Profile.groveRecordingDevice) == true) + let provenance = try #require(watchBundle.entry?.compactMap { $0.resource?.get(if: Provenance.self) }.first) + let recorderURL = try #require(watchBundle.entry?.first { $0.resource?.get(if: Device.self) == recorder }?.fullUrl?.value?.url.absoluteString) + let author = provenance.entity?.first?.agent?.first { agent in + agent.type?.coding?.contains { $0.code?.value?.string == "author" } == true + } + #expect(author?.who.reference?.value?.string == recorderURL) + #expect(exports[0].warnings.isEmpty) + // The application source converts exactly as the old entry point's default (`.application`) did. + let reference = try Self.reference(fromApp, exporter: exporter, sequence: 2, instant: GoldenFixtures.conversionInstant) + #expect(exports[1].graph?.json == reference.graph.json) + } + + @Test("The omit policies state nothing and never warn; the legacy Bundle.id keeps the HealthKit UUID") + func policiesApply() throws { + let exporter = try Self.exporter { options in + options.recordingDevice = .omit + options.writer = .omit + options.legacyBundleID = .healthKitUUID + options.nativeIdentifier = .authorized(system: GoldenFixtures.nativeIdentifierSystem) + options.udi = .authorized + options.role = .gatewayForOwnWrites + } + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(9), device: GoldenFixtures.watchWithoutUnitToken, writer: GoldenFixtures.foreignWriter) + let (exports, _) = try Self.collect(exporter, [sample]) + let bundle = try #require(exports[0].graph?.bundle) + #expect(exports[0].warnings.isEmpty) + #expect(bundle.id?.value?.string == GoldenFixtures.uuid(9).uuidString) + let devices = bundle.entry?.compactMap { $0.resource?.get(if: Device.self) } ?? [] + #expect(devices.allSatisfy { $0.meta?.profile?.contains(Profile.groveRecordingDevice) == false }) + #expect(bundle.entry?.compactMap { $0.resource?.get(if: Provenance.self) }.first?.entity?.first?.agent == nil) + let observation = try #require(bundle.entry?.compactMap { $0.resource?.get(if: Observation.self) }.first) + #expect(observation.identifier?.contains { $0.system?.value?.url.absoluteString == GoldenFixtures.nativeIdentifierSystem.rawValue } == true) + let reference = try Self.reference(sample, exporter: exporter, sequence: 1, instant: GoldenFixtures.conversionInstant) { options in + options.writer = .omit + options.udiDisclosure = .authorizedUDI + options.nativeIdentifierDisclosure = .authorized(system: GoldenFixtures.nativeIdentifierSystem) + } + // Only `Bundle.id` differs from the entry point's graph under the same policies. + var expected = reference.graph.bundle + expected.id = GoldenFixtures.uuid(9).uuidString.asFHIRStringPrimitive() + #expect(bundle == expected) + } + + @Test("A native identifier under a deployment system is refused at configuration") + func reservedNativeIdentifierSystemIsRefused() throws { + let system = Self.base.identityScope.systems.opaque.sourceRecord + #expect(throws: HealthKitFHIRExporter.ConfigurationError.reservedNativeIdentifierSystem(system)) { + try Self.exporter { $0.nativeIdentifier = .authorized(system: system) } + } + } + + @Test("Retractions take their own events and recompute the targets the old entry point computed") + func retractionsMatchReference() throws { + let exporter = try Self.exporter() + let detectedAt = GoldenFixtures.conversionInstant + let deletions = [ + HealthKitFHIRExporter.Deletion(uuid: GoldenFixtures.uuid(10), sourceType: .heartRate, deletedAfter: GoldenFixtures.sampleStart, detectedAt: detectedAt), + HealthKitFHIRExporter.Deletion(uuid: GoldenFixtures.uuid(11), sourceType: .bloodPressureSystolic, deletedAfter: nil, detectedAt: detectedAt), + HealthKitFHIRExporter.Deletion(uuid: GoldenFixtures.uuid(12), sourceType: .bloodPressure, deletedAfter: nil, detectedAt: detectedAt) + ] + var exports: [HealthKitFHIRExporter.Export] = [] + let receipt = try exporter.retract(deletions, at: detectedAt) { exports.append($0) } + try #require(exports.count == 3) + guard case .nothingToRetract = exports[0].outcome else { + Issue.record("a systolic component never emitted outputs; expected nothingToRetract, got \(exports[0].outcome)") + return + } + #expect(exports[0].source.uuid == GoldenFixtures.uuid(11)) + #expect(exports[1].source.uuid == GoldenFixtures.uuid(10)) + #expect(exports[2].source.uuid == GoldenFixtures.uuid(12)) + let producerInstance = try exporter.producer.sequencer.producerInstance + for (export, sequence, deletion) in [(exports[1], UInt64(1), deletions[0]), (exports[2], 2, deletions[2])] { + let context = HealthKitConversionContext(event: ExchangeEventContext( + subject: Self.base.subject, + event: try ExchangeEventIdentifier(system: Self.base.identityScope.systems.event, producerInstance: producerInstance, sequence: EventSequence(sequence)), + identityScope: Self.base.identityScope, + repositoryScope: Self.base.repositoryScope, + application: Self.base.application, + host: Self.base.host, + conversionInstant: detectedAt + )) + let reference = try HealthKitConverter.retraction( + for: HealthKitSourceRecord(uuid: deletion.uuid, type: deletion.sourceType), + context: context, + occurred: .period(start: deletion.deletedAfter, end: detectedAt) + ) + #expect(export.graph?.json == reference.graph.json) + } + receipt.release() + let (afterRelease, _) = try Self.collect(exporter, [try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(13))]) + #expect(afterRelease[0].graph?.event.value.hasSuffix(":3") == true) + } + + @Test("An export shares one receipt; an error in the receiver ends the call with the reservations kept") + func receiverErrorsPropagate() throws { + struct Stop: Error {} + let exporter = try Self.exporter() + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(14)) + #expect(throws: Stop.self) { + try exporter.export([sample]) { _ in throw Stop() } + } + let (again, _) = try Self.collect(exporter, [sample]) + #expect(again[0].graph?.event.value.hasSuffix(":1") == true) + } +} + +#endif From 12b034507a6e93c9a85f9b42a04d094d1ee0a037 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sat, 3 Oct 2026 13:39:08 +0200 Subject: [PATCH 005/220] Keep Refusals Typed and Retractions Keyed Like Additions A refused record reports its `HealthKitConversionError` rather than only the registered diagnostic, so a consumer can match the reason; a retraction carries the same legacy `Bundle.id` as the addition it retracts; a deletion lower bound that a backwards clock adjustment put after the detection is dropped instead of clamped; and an export or retraction with nothing to reserve never touches the sequencer's ledger. Co-Authored-By: Claude Fable 5.1 --- .../HealthKitFHIRExporter+Results.swift | 5 +- .../HealthKitFHIRExporter+Retraction.swift | 12 +++-- .../HealthKitFHIRExporter.swift | 13 +++-- .../HealthKitFHIRExporterTests.swift | 48 ++++++++++++++++++- 4 files changed, 62 insertions(+), 16 deletions(-) diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift index 37614bde1..a12bf6d87 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift @@ -73,8 +73,9 @@ extension HealthKitFHIRExporter { public enum Outcome: Sendable { /// The validated graph; store or upload ``ExchangeGraph/json`` verbatim. case graph(ExchangeGraph) - /// The record was refused with a registered diagnostic; nothing was emitted and the export continued. - case refused(ProducerDiagnostic) + /// The record was refused; nothing was emitted and the export continued. Refusals are + /// deterministic, so an exact redelivery refuses identically. + case refused(HealthKitConversionError) /// A deletion of a source type that never emits outputs. case nothingToRetract } diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift index a9df4c586..c0b20ea0f 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift @@ -25,8 +25,8 @@ extension HealthKitFHIRExporter { ) throws -> Receipt { let retractable = deletions.filter { !HealthKitCatalog.outputs(for: $0.sourceType).isEmpty } let keys = retractable.map(ExchangeEventKey.retraction) - let reservations = try producer.sequencer.reserve(keys, at: instant) - let producerInstance = try producer.sequencer.producerInstance + let reservations = keys.isEmpty ? [] : try producer.sequencer.reserve(keys, at: instant) + let producerInstance = keys.isEmpty ? UUID() : try producer.sequencer.producerInstance for deletion in deletions where HealthKitCatalog.outputs(for: deletion.sourceType).isEmpty { try receive(Export(source: deletion.source, outcome: .nothingToRetract, warnings: [])) } @@ -36,7 +36,7 @@ extension HealthKitFHIRExporter { outcome = .graph(try retraction(of: deletion, reservation: reservation, producerInstance: producerInstance)) } catch { producer.sequencer.releaseIgnoringErrors([ExchangeEventKey.retraction(deletion)]) - outcome = .refused(HealthKitConversionError(conversionFailure: error, source: deletion.sourceType).diagnostic) + outcome = .refused(HealthKitConversionError(conversionFailure: error, source: deletion.sourceType)) } try receive(Export(source: deletion.source, outcome: outcome, warnings: [])) } @@ -62,15 +62,17 @@ extension HealthKitFHIRExporter { conversionInstant: reservation.instant, converterRole: .assembler, studies: producer.studies, - repositoryIDs: [:] + repositoryIDs: try legacyRepositoryIDs(for: deletion.uuid) ) let context = HealthKitConversionContext( event: event, options: HealthKitConversionOptions(nativeIdentifierDisclosure: options.nativeIdentifier) ) let record = HealthKitSourceRecord(uuid: deletion.uuid, type: deletion.sourceType) + // A backwards clock adjustment can put the earlier query after the detection; keep the known + // upper bound rather than stating an invalid period. let occurred = RetractionOccurrence.period( - start: deletion.deletedAfter.map { min($0, deletion.detectedAt) }, + start: deletion.deletedAfter.flatMap { $0 <= deletion.detectedAt ? $0 : nil }, end: deletion.detectedAt ) return try HealthKitConverter.retraction(for: record, context: context, occurred: occurred).graph diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift index ac6e6160f..3d3e8aa0d 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift @@ -66,8 +66,9 @@ public final class HealthKitFHIRExporter: Sendable { ) throws -> Receipt { let plans = records.map(Plan.init) let keys = plans.flatMap(\.keys) - let reservations = try producer.sequencer.reserve(keys, at: instant) - let producerInstance = try producer.sequencer.producerInstance + // Nothing reserved means the ledger is never touched; refusals alone need no producer instance. + let reservations = keys.isEmpty ? [] : try producer.sequencer.reserve(keys, at: instant) + let producerInstance = keys.isEmpty ? UUID() : try producer.sequencer.producerInstance var offset = 0 for plan in plans { let reserved = Array(reservations[offset..<(offset + plan.keys.count)]) @@ -87,7 +88,7 @@ extension HealthKitFHIRExporter { struct Plan { let record: Record let keys: [ExchangeEventKey] - let refusal: ProducerDiagnostic? + let refusal: HealthKitConversionError? var source: Export.Source { Export.Source(uuid: record.sample.uuid, typeIdentifier: record.sample.sampleType.identifier) @@ -110,7 +111,7 @@ extension HealthKitFHIRExporter { } catch { let failure = HealthKitConversionError(conversionFailure: error, source: plan.source.sourceType) producer.sequencer.releaseIgnoringErrors(plan.keys) - try receive(Export(source: plan.source, outcome: .refused(failure.diagnostic), warnings: [])) + try receive(Export(source: plan.source, outcome: .refused(failure), warnings: [])) return } guard let set else { @@ -179,9 +180,7 @@ extension HealthKitFHIRExporter.Plan { keys += symptoms.compactMap(ExchangeEventKey.active) } self.keys = keys - self.refusal = keys.isEmpty - ? HealthKitConversionError.unregisteredSourceType(record.sample.sampleType.identifier).diagnostic - : nil + self.refusal = keys.isEmpty ? .unregisteredSourceType(record.sample.sampleType.identifier) : nil } } diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift index 7262a5057..4152fb97b 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift @@ -16,6 +16,21 @@ import ModelsR4 import Testing +/// Counts the ledger writes a sequencer makes. +private final class CountingStorage: ExchangeEventSequencer.Storage, @unchecked Sendable { + private let lock = NSLock() + private var data: Data? + private(set) var updates = 0 + + func update(_ body: (inout Data?) throws -> R) throws -> R { + lock.lock() + defer { lock.unlock() } + updates += 1 + return try body(&data) + } +} + + /// The exporter is a facade over the conversion the goldens pin: its graphs are byte-identical to the old /// entry point's under the same event, and it adds the event bookkeeping and policies the entry point left /// to the caller. @@ -123,11 +138,11 @@ struct HealthKitFHIRExporterTests { let heartRate = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(5)) let (exports, _) = try Self.collect(exporter, [ecg, heartRate]) try #require(exports.count == 2) - guard case .refused(let diagnostic) = exports[0].outcome else { + guard case .refused(let reason) = exports[0].outcome else { Issue.record("expected a refusal, got \(exports[0].outcome)") return } - #expect(diagnostic == HealthKitConversionError.ecgEvidence(.evidenceRequired).diagnostic) + #expect(reason == .ecgEvidence(.evidenceRequired)) #expect(exports[0].graph == nil) #expect(exports[1].graph?.event.value.hasSuffix(":2") == true) // The refused ECG's reservation was released, so the next export of it takes a fresh sequence. @@ -251,6 +266,34 @@ struct HealthKitFHIRExporterTests { #expect(afterRelease[0].graph?.event.value.hasSuffix(":3") == true) } + @Test("Deletions of types without outputs touch no ledger; a skewed lower bound is dropped, Bundle.id follows the legacy policy") + func retractionBoundsAndLedger() throws { + let storage = CountingStorage() + let exporter = try Self.exporter({ $0.legacyBundleID = .healthKitUUID }, sequencer: ExchangeEventSequencer(storage: storage)) + let detectedAt = GoldenFixtures.conversionInstant + var exports: [HealthKitFHIRExporter.Export] = [] + _ = try exporter.retract( + [HealthKitFHIRExporter.Deletion(uuid: GoldenFixtures.uuid(20), sourceType: .bloodPressureSystolic, deletedAfter: nil, detectedAt: detectedAt)], + at: detectedAt + ) { exports.append($0) } + #expect(storage.updates == 0) + _ = try exporter.export([HKSample](), at: detectedAt) { exports.append($0) } + #expect(storage.updates == 0) + _ = try exporter.retract( + [HealthKitFHIRExporter.Deletion(uuid: GoldenFixtures.uuid(21), sourceType: .heartRate, deletedAfter: detectedAt + 60, detectedAt: detectedAt)], + at: detectedAt + ) { exports.append($0) } + let bundle = try #require(exports.last?.graph?.bundle) + #expect(bundle.id?.value?.string == GoldenFixtures.uuid(21).uuidString) + let provenance = try #require(bundle.entry?.compactMap { $0.resource?.get(if: Provenance.self) }.first) + guard case .period(let period)? = provenance.occurred else { + Issue.record("expected a period") + return + } + #expect(period.start == nil) + #expect(period.end != nil) + } + @Test("An export shares one receipt; an error in the receiver ends the call with the reservations kept") func receiverErrorsPropagate() throws { struct Stop: Error {} @@ -264,4 +307,5 @@ struct HealthKitFHIRExporterTests { } } + #endif From 00c86249ca9a8a1bec3ce77b1f513e063075c6f5 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sat, 3 Oct 2026 14:07:32 +0200 Subject: [PATCH 006/220] Assemble Every HealthKit Graph Through One Shared Assembler The graph envelope (output identities and links, study context, device snapshots, writer deduplication, conversion Provenance, Bundle framing) moves into a package-level `ExchangeGraphAssembler` in GroveFHIRContract. An adapter describes one event as an `ExchangeGraphDraft`: content-only outputs with the envelope links each takes, the resolved recording device and writer, and the event's role and repository ids. The assembler mints every identity once, computes each fullUrl once, and builds the graph in the guide's fixed entry order. On the HealthKit side, `HealthKitAssembly` replaces the static `HealthKitConverter` pipeline: `SourceFacts` resolves what a sample says about its origin (recording device, writer, native and writer-record identifiers, withheld metadata) in one place, and the content builders (Observation, workout segments, ECG and its average heart rate, recording documents) no longer reach into an envelope. The old envelope code (`GraphEnvelope`, `GraphChildOutput`, `HealthKitGraphContext`, the device and sync-identity helpers) is deleted. `HealthKitFHIRExporter` converts through the assembly directly; the deprecated `HealthKitConverter` entry points forward to it until they are removed. Output is unchanged: the 40 golden graphs match byte for byte. Tests that exercised the deleted internal seams reach the same behaviour through a test-only seam file. Co-Authored-By: Claude Opus 5.5 --- .../ExchangeGraphAssembler+Devices.swift | 231 +++++++++ .../ExchangeGraphAssembler.swift | 335 +++++++++++++ .../ExchangeGraphDraft.swift | 236 +++++++++ .../HealthKitAssembly+Records.swift | 269 +++++++++++ .../HealthKitAssembly+SourceFacts.swift | 216 +++++++++ .../HealthKitAssembly.swift | 197 ++++++++ .../HealthKitConversionError.swift | 4 + .../HealthKitConverter+ClinicalDocument.swift | 43 +- .../HealthKitConverter+Devices.swift | 334 ------------- .../HealthKitConverter+ECG.swift | 41 +- .../HealthKitConverter+ECGCore.swift | 203 +------- .../HealthKitConverter+GraphAssembly.swift | 447 ------------------ .../HealthKitConverter+IdentityMetadata.swift | 106 ----- .../HealthKitConverter+Observation.swift | 10 +- ...ealthKitConverter+RecordingDocuments.swift | 124 +---- .../HealthKitConverter+Retraction.swift | 96 +--- .../HealthKitConverter+WorkoutSegments.swift | 56 +-- .../HealthKitConverter.swift | 50 +- .../HealthKitECGGraphInput.swift | 10 - .../HealthKitFHIRExporter+Retraction.swift | 18 +- .../HealthKitFHIRExporter.swift | 63 ++- .../ConformanceFixtureTests.swift | 25 +- .../ConversionThroughputBenchmark.swift | 30 +- .../GoldenGraphCases+Documents.swift | 2 +- .../HealthKitConverter+TestSeams.swift | 108 +++++ 25 files changed, 1734 insertions(+), 1520 deletions(-) create mode 100644 Sources/GroveFHIRContract/ExchangeGraphAssembler+Devices.swift create mode 100644 Sources/GroveFHIRContract/ExchangeGraphAssembler.swift create mode 100644 Sources/GroveFHIRContract/ExchangeGraphDraft.swift create mode 100644 Sources/GroveHealthKitFHIR/HealthKitAssembly+Records.swift create mode 100644 Sources/GroveHealthKitFHIR/HealthKitAssembly+SourceFacts.swift create mode 100644 Sources/GroveHealthKitFHIR/HealthKitAssembly.swift delete mode 100644 Sources/GroveHealthKitFHIR/HealthKitConverter+Devices.swift delete mode 100644 Sources/GroveHealthKitFHIR/HealthKitConverter+GraphAssembly.swift delete mode 100644 Sources/GroveHealthKitFHIR/HealthKitConverter+IdentityMetadata.swift create mode 100644 Tests/GroveHealthKitFHIRTests/HealthKitConverter+TestSeams.swift diff --git a/Sources/GroveFHIRContract/ExchangeGraphAssembler+Devices.swift b/Sources/GroveFHIRContract/ExchangeGraphAssembler+Devices.swift new file mode 100644 index 000000000..243c7eb20 --- /dev/null +++ b/Sources/GroveFHIRContract/ExchangeGraphAssembler+Devices.swift @@ -0,0 +1,231 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +// Literal formatting follows FHIR resource shape. +// swiftlint:disable multiline_literal_brackets + +import Foundation +import ModelsR4 + + +// MARK: - Devices + +extension ExchangeGraphAssembler { + struct ConverterSnapshots { + let host: IdentifiedDevice + let application: IdentifiedDevice + let applicationURL: String + /// A distinct application that mediated the measurement; `gatewayURL` names the converter itself when it did. + let gateway: IdentifiedDevice? + let gatewayURL: String? + + var identities: Set { + Set([host.identity, application.identity] + (gateway.map { [$0.identity] } ?? [])) + } + } + + struct RecordingSnapshot { + let device: IdentifiedDevice + let url: String + } + + struct WriterSnapshots { + let application: IdentifiedDevice + let host: IdentifiedDevice + let applicationURL: String + /// The writer snapshots the graph carries as entries of their own: none when the converter + /// already states the application, and the host only when the converter does not state it. + let entries: [IdentifiedDevice] + } + + /// The writer snapshots a graph carries as entries of their own. A snapshot the converter already + /// states is that entry, and the host of a writer that is the converter's application has nothing + /// to connect to. + package static func writerEntries( + application: IdentifiedDevice, + host: IdentifiedDevice, + stated: Set + ) -> [IdentifiedDevice] { + guard !stated.contains(application.identity) else { + return [] + } + return [host].filter { !stated.contains($0.identity) } + [application] + } + + func resolveDevices(for draft: ExchangeGraphDraft) throws -> Devices { + let converter = try converterSnapshots(event: draft.event, repositoryIDs: draft.repositoryIDs, role: draft.converterRole) + let recording = try recordingSnapshot(draft.recordingDevice, event: draft.event, repositoryIDs: draft.repositoryIDs) + let writer = try writerSnapshots(draft.writer, event: draft.event, repositoryIDs: draft.repositoryIDs, converter: converter) + if draft.repositoryIDs[.recordingDevice] != nil, recording == nil { + throw ExchangeAssemblyError.repositoryIDWithoutNode(.recordingDevice) + } + let writerEntries = Set(writer?.entries.map(\.identity) ?? []) + if draft.repositoryIDs[.writer] != nil, !writerEntries.contains(where: { $0 == writer?.application.identity }) { + throw ExchangeAssemblyError.repositoryIDWithoutNode(.writer) + } + if draft.repositoryIDs[.writerHost] != nil, !writerEntries.contains(where: { $0 == writer?.host.identity }) { + throw ExchangeAssemblyError.repositoryIDWithoutNode(.writerHost) + } + let authorURL: String? = switch draft.writer { + case .application: writer?.applicationURL + case .recordingDevice: recording?.url + case nil: nil + } + return Devices(converter: converter, recording: recording, writer: writer, authorURL: authorURL) + } + + private func converterSnapshots( + event: ExchangeEventIdentifier, + repositoryIDs: [ExchangeGraphNode: RepositoryID], + role: ConverterRole + ) throws -> ConverterSnapshots { + let host = try hostSnapshot(envelope.host, event: event, repositoryID: repositoryIDs[.hostDevice]) + let application = try applicationSnapshot( + envelope.application, + event: event, + parentURL: try host.identity.fullURLString, + repositoryID: repositoryIDs[.applicationDevice] + ) + let applicationURL = try application.identity.fullURLString + switch role { + case .assembler: + return ConverterSnapshots(host: host, application: application, applicationURL: applicationURL, gateway: nil, gatewayURL: nil) + case .gateway: + return ConverterSnapshots(host: host, application: application, applicationURL: applicationURL, gateway: nil, gatewayURL: applicationURL) + case .gatewayApplication(let gatewayApplication): + let gateway = try applicationSnapshot(gatewayApplication, event: event, parentURL: nil, repositoryID: nil) + return ConverterSnapshots( + host: host, + application: application, + applicationURL: applicationURL, + gateway: gateway, + gatewayURL: try gateway.identity.fullURLString + ) + } + } + + private func recordingSnapshot( + _ draft: ExchangeRecordingDeviceDraft?, + event: ExchangeEventIdentifier, + repositoryIDs: [ExchangeGraphNode: RepositoryID] + ) throws -> RecordingSnapshot? { + guard let draft else { + return nil + } + let scope = envelope.identityScope + let stable = try scope.recordingDevice( + adapterID: envelope.adapter.adapterID, + subject: envelope.subject.identifier, + stableUnitToken: draft.device.stableUnitToken + ) + let snapshot = try scope.deviceSnapshot(event: event, role: .recordingDevice, sourceDeviceToken: draft.device.stableUnitToken) + var resource = draft.resource + resource.id = repositoryIDs[.recordingDevice]?.primitive + resource.identifier = [snapshot.fhirIdentifier, stable.fhirIdentifier] + return RecordingSnapshot(device: IdentifiedDevice(resource: resource, identity: snapshot), url: try snapshot.fullURLString) + } + + private func writerSnapshots( + _ writer: ExchangeWriterDraft?, + event: ExchangeEventIdentifier, + repositoryIDs: [ExchangeGraphNode: RepositoryID], + converter: ConverterSnapshots + ) throws -> WriterSnapshots? { + guard case let .application(application, hostDevice, statesVersion) = writer else { + return nil + } + let host = try hostSnapshot(hostDevice, event: event, repositoryID: repositoryIDs[.writerHost]) + var snapshot = try applicationSnapshot( + application, + event: event, + parentURL: try host.identity.fullURLString, + repositoryID: repositoryIDs[.writer] + ) + if !statesVersion { + var resource = snapshot.resource + resource.version = nil + snapshot = IdentifiedDevice(resource: resource, identity: snapshot.identity) + } + return WriterSnapshots( + application: snapshot, + host: host, + applicationURL: try snapshot.identity.fullURLString, + entries: Self.writerEntries(application: snapshot, host: host, stated: converter.identities) + ) + } + + + private func hostSnapshot(_ host: HostDevice, event: ExchangeEventIdentifier, repositoryID: RepositoryID?) throws -> IdentifiedDevice { + let identity = try envelope.identityScope.deviceSnapshot(event: event, role: .host, sourceDeviceToken: host.sourceDeviceToken) + var resource = hostDevice(host) + resource.id = repositoryID?.primitive + resource.identifier = [identity.fhirIdentifier] + return IdentifiedDevice(resource: resource, identity: identity) + } + + private func applicationSnapshot( + _ application: ApplicationDevice, + event: ExchangeEventIdentifier, + parentURL: String?, + repositoryID: RepositoryID? + ) throws -> IdentifiedDevice { + let identity = try envelope.identityScope.deviceSnapshot( + event: event, + role: .application, + sourceDeviceToken: application.sourceDeviceToken + ) + var resource = applicationDevice(application) + resource.id = repositoryID?.primitive + resource.identifier = [identity.fhirIdentifier] + (resource.identifier ?? []) + resource.parent = parentURL.map { Reference(reference: $0.asFHIRStringPrimitive()) } + return IdentifiedDevice(resource: resource, identity: identity) + } + + private func applicationDevice(_ application: ApplicationDevice) -> Device { + var device = Device() + device.meta = Meta(profile: [envelope.adapter.applicationDeviceProfile]) + device.status = FHIRPrimitive(.active) + device.identifier = envelope.adapter.applicationIdentifier?(application).map { [$0] } + device.deviceName = [DeviceDeviceName(name: application.name.asFHIRStringPrimitive(), type: FHIRPrimitive(.userFriendlyName))] + var versions = [DeviceVersion( + type: CodeableConcept(coding: [Coding(code: "531975", display: "MDC_ID_PROD_SPEC_SW", system: Canonicals.mdc)]), + value: application.version.asFHIRStringPrimitive() + )] + if let build = application.build { + versions.append(groveVersion("build", "Build", build)) + } + device.version = versions + return device + } + + private func hostDevice(_ host: HostDevice) -> Device { + var device = Device() + device.meta = Meta(profile: [Profile.groveHostDevice]) + device.status = FHIRPrimitive(.active) + if let name = host.name { + device.deviceName = [DeviceDeviceName(name: name.asFHIRStringPrimitive(), type: FHIRPrimitive(.userFriendlyName))] + } + device.manufacturer = host.manufacturer?.asFHIRStringPrimitive() + device.modelNumber = host.modelNumber?.asFHIRStringPrimitive() + device.version = [groveVersion("os-version", "Operating system version", host.operatingSystemVersion)] + return device + } + + private func groveVersion(_ code: String, _ display: String, _ value: String) -> DeviceVersion { + DeviceVersion( + type: CodeableConcept(coding: [Coding( + code: code.asFHIRStringPrimitive(), + display: display.asFHIRStringPrimitive(), + system: Canonicals.groveApplicationVersionType + )]), + value: value.asFHIRStringPrimitive() + ) + } +} + +// swiftlint:enable multiline_literal_brackets diff --git a/Sources/GroveFHIRContract/ExchangeGraphAssembler.swift b/Sources/GroveFHIRContract/ExchangeGraphAssembler.swift new file mode 100644 index 000000000..c1aacdaeb --- /dev/null +++ b/Sources/GroveFHIRContract/ExchangeGraphAssembler.swift @@ -0,0 +1,335 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +// Literal formatting follows FHIR resource shape. +// swiftlint:disable multiline_literal_brackets + +import Foundation +import ModelsR4 + + +/// Builds the one exchange graph shape every adapter emits: outputs decorated with the event's +/// identities and links, the study context, the device snapshots, the conversion Provenance, and the +/// Bundle header, in the fixed entry order the guide validates. +/// +/// Every identity is minted once and its fullUrl computed once. The adapter supplies content; the +/// assembler supplies everything the graph says about the event, the producer and the record. +package struct ExchangeGraphAssembler: Sendable { + /// What every output of one graph may link to, resolved once per graph. + struct Surroundings { + let subject: Reference + let studyReferences: [Reference] + let recordingURL: String? + let gatewayURL: String? + let converterURL: String + } + + /// The device snapshots of one graph and who the Provenance names as author. + struct Devices { + let converter: ConverterSnapshots + let recording: RecordingSnapshot? + let writer: WriterSnapshots? + let authorURL: String? + + /// Every Device entry, in its fixed order. + var entries: [IdentifiedDevice] { + var entries: [IdentifiedDevice] = [] + if let recording { + entries.append(recording.device) + } + entries += [converter.host, converter.application] + if let gateway = converter.gateway { + entries.append(gateway) + } + return entries + (writer?.entries ?? []) + } + } + + struct DecoratedOutput { + let identity: RoledIdentifier + let url: String + let artifact: RoledIdentifier? + var resource: ExchangeOutputDraft.Resource + } + + package let envelope: ExchangeEnvelope + + package init(envelope: ExchangeEnvelope) { + self.envelope = envelope + } + + /// Assembles, encodes and validates one event's graph. + package func assemble(_ draft: ExchangeGraphDraft) throws -> AssembledExchangeGraph { + guard !draft.outputs.isEmpty else { + throw ExchangeAssemblyError.noOutputs + } + let studyContext = try eventContext(for: draft).studyContext() + let devices = try resolveDevices(for: draft) + let surroundings = Surroundings( + subject: studyContext.subjectReference, + studyReferences: studyContext.studyReferences, + recordingURL: devices.recording?.url, + gatewayURL: devices.converter.gatewayURL, + converterURL: devices.converter.applicationURL + ) + let outputs = try decoratedOutputs(of: draft, surroundings: surroundings) + let provenanceNode = try EntryNodeKey( + system: envelope.identityScope.systems.entryNode, + event: draft.event, + nodeRole: "conversion-provenance", + ordinal: 0 + ) + var provenance = try provenance( + sourceIdentifier: draft.sourceRecord.identifier.fhirIdentifier, + targetURLs: outputs.map(\.url), + converterURL: devices.converter.applicationURL, + authorURL: devices.authorURL, + recordedAt: draft.instant + ) + provenance.id = draft.repositoryIDs[.provenance]?.primitive + + var entries = try outputs.map { try BundleEntry(identifier: $0.identity, resource: $0.resource.proxy) } + entries.append(contentsOf: studyContext.allEntries) + entries.append(contentsOf: try devices.entries.map { try BundleEntry(identifier: $0.identity, resource: ResourceProxy(with: $0.resource)) }) + entries.append(try BundleEntry(identifier: provenanceNode.identifier, resource: ResourceProxy(with: provenance))) + return AssembledExchangeGraph( + graph: try graph(entries: entries, draft: draft), + identifiers: ExchangeGraphIdentifiers( + event: draft.event.identifier, + sourceRecord: draft.sourceRecord.identifier, + primaryOutput: outputs[0].identity, + applicationSnapshot: devices.converter.application.identity, + hostSnapshot: devices.converter.host.identity, + provenance: provenanceNode.identifier, + childOutputs: outputs.dropFirst().map(\.identity), + sourceArtifact: outputs[0].artifact, + recordingDeviceSnapshot: devices.recording?.device.identity, + writerSnapshot: devices.writer?.application.identity, + writerHostSnapshot: devices.writer?.entries.isEmpty == false ? devices.writer?.host.identity : nil + ) + ) + } + + /// The validated graph of one event's entries, in the order given. + private func graph(entries: [BundleEntry], draft: ExchangeGraphDraft) throws -> ExchangeGraph { + var bundle = Bundle( + entry: entries, + identifier: draft.event.identifier.fhirIdentifier, + meta: Meta(profile: [Profile.groveMobileExchangeBundle]), + timestamp: FHIRPrimitive(try Instant(utc: draft.instant)), + type: FHIRPrimitive(.collection) + ) + bundle.id = draft.repositoryIDs[.bundle]?.primitive + return try ExchangeGraph(kind: .active, eventIdentifier: draft.event, bundle: bundle) + } + + /// The context the study entries are minted from; the subject and enrollments never vary per event. + private func eventContext(for draft: ExchangeGraphDraft) -> ExchangeEventContext { + ExchangeEventContext( + subject: envelope.subject, + event: draft.event, + identityScope: envelope.identityScope, + repositoryScope: envelope.repositoryScope, + application: envelope.application, + host: envelope.host, + conversionInstant: draft.instant, + converterRole: draft.converterRole, + studies: envelope.studies, + repositoryIDs: draft.repositoryIDs + ) + } +} + + +// MARK: - Outputs + +extension ExchangeGraphAssembler { + private static let manualEntry = Extension( + url: Canonicals.recordingMethod, + value: .coding(Coding(code: "manual-entry", display: "Manual entry", system: Canonicals.recordingMethodCodeSystem)) + ) + + /// Every output with its identities and links applied; in-graph members are linked from the primary. + private func decoratedOutputs(of draft: ExchangeGraphDraft, surroundings: Surroundings) throws -> [DecoratedOutput] { + var outputs: [DecoratedOutput] = [] + for (index, output) in draft.outputs.enumerated() { + outputs.append(try decorate(output, isPrimary: index == 0, draft: draft, surroundings: surroundings)) + } + let primaryURL = outputs[0].url + for (index, output) in draft.outputs.enumerated() where output.derivedFromPrimary && index > 0 { + if case .observation(var observation) = outputs[index].resource { + observation.derivedFrom = [Reference(reference: primaryURL.asFHIRStringPrimitive())] + outputs[index].resource = .observation(observation) + } + } + let memberURLs = zip(draft.outputs, outputs).filter { $0.0.memberOfPrimary }.map(\.1.url) + if !memberURLs.isEmpty, case .observation(var observation) = outputs[0].resource { + observation.hasMember = (observation.hasMember ?? []) + memberURLs.map { Reference(reference: $0.asFHIRStringPrimitive()) } + outputs[0].resource = .observation(observation) + } + return outputs + } + + private func decorate( + _ output: ExchangeOutputDraft, + isPrimary: Bool, + draft: ExchangeGraphDraft, + surroundings: Surroundings + ) throws -> DecoratedOutput { + let identity = try draft.sourceRecord.output(role: output.role, discriminator: output.discriminator) + let artifact = try output.artifactFormatCode.map { try draft.sourceRecord.artifact(formatCode: $0, partIndex: 0) } + let writerRecord = try output.writerRecord.map(writerRecordIdentity) + var identifiers = [draft.sourceRecord.identifier.fhirIdentifier, identity.fhirIdentifier] + if let artifact { + identifiers.append(artifact.fhirIdentifier) + } + identifiers += output.clearIdentifiers + if let writerRecord { + identifiers.append(writerRecord.identity.fhirIdentifier) + } + let repositoryID = isPrimary ? draft.repositoryIDs[.primaryOutput]?.primitive : nil + let resource: ExchangeOutputDraft.Resource + switch output.resource { + case .observation(var observation): + observation.id = repositoryID + observation.identifier = identifiers + decorate(&observation, links: output.links, wasUserEntered: output.wasUserEntered, surroundings: surroundings) + if let writerRecord { + observation.extension.append(Extension( + url: Canonicals.writerRecordVersion, + value: .string(writerRecord.version.asFHIRStringPrimitive()) + )) + } + resource = .observation(observation) + case .document(var document): + document.id = repositoryID + document.identifier = identifiers + document.date = FHIRPrimitive(try Instant(utc: draft.instant)) + decorate(&document, links: output.links, surroundings: surroundings) + resource = .document(document) + } + return DecoratedOutput(identity: identity, url: try identity.fullURLString, artifact: artifact, resource: resource) + } + + private func decorate( + _ observation: inout Observation, + links: ExchangeOutputDraft.Links, + wasUserEntered: Bool, + surroundings: Surroundings + ) { + if links.contains(.subject) { + observation.subject = surroundings.subject + } + if links.contains(.recordingDevice), let recordingURL = surroundings.recordingURL { + observation.device = Reference(reference: recordingURL.asFHIRStringPrimitive()) + } + if links.contains(.manualEntry), wasUserEntered { + observation.extension.replace(Self.manualEntry) + } + if links.contains(.gateway), let gatewayURL = surroundings.gatewayURL { + observation.extension.replace( + Extension(url: Canonicals.gatewayDevice, value: .reference(Reference(reference: gatewayURL.asFHIRStringPrimitive()))) + ) + } + if links.contains(.studies) { + for study in surroundings.studyReferences { + observation.extension.append(Extension(url: Canonicals.researchStudy, value: .reference(study))) + } + } + } + + private func decorate(_ document: inout DocumentReference, links: ExchangeOutputDraft.Links, surroundings: Surroundings) { + if links.contains(.subject) { + document.subject = surroundings.subject + } + if links.contains(.recordingDevice) { + document.author = [surroundings.recordingURL, surroundings.converterURL].compactMap { url in + url.map { Reference(reference: $0.asFHIRStringPrimitive()) } + } + } + if links.contains(.studies), !surroundings.studyReferences.isEmpty { + document.context = DocumentReferenceContext(related: surroundings.studyReferences) + } + } + + private func writerRecordIdentity(_ record: ExchangeOutputDraft.WriterRecord) throws -> (identity: RoledIdentifier, version: String) { + let identity = try envelope.identityScope.writerRecord( + writerApplication: BusinessIdentifier( + system: IdentifierSystem(Canonicals.appleBundleIdentifierSystem), + value: record.writerApplication + ), + writerRecordID: record.syncIdentifier + ) + return (identity, record.version) + } +} + + +// MARK: - Provenance + +extension ExchangeGraphAssembler { + private func provenance( + sourceIdentifier: Identifier, + targetURLs: [String], + converterURL: String, + authorURL: String?, + recordedAt: Date + ) throws -> Provenance { + var entity = ProvenanceEntity(role: FHIRPrimitive(.source), what: Reference(identifier: sourceIdentifier)) + entity.agent = authorURL.map { url in + [ProvenanceAgent( + type: CodeableConcept(coding: [Coding(code: "author", display: "Author", system: Canonicals.provenanceParticipantType)]), + who: Reference(reference: url.asFHIRStringPrimitive()) + )] + } + return Provenance( + activity: CodeableConcept(coding: [Coding( + code: "transform", + display: "Transform/Translate Record Lifecycle Event", + system: Canonicals.isoLifecycleEvent + )]), + agent: [ProvenanceAgent( + type: CodeableConcept(coding: [Coding(code: "assembler", display: "Assembler", system: Canonicals.provenanceParticipantType)]), + who: Reference(reference: converterURL.asFHIRStringPrimitive()) + )], + entity: [entity], + meta: Meta(profile: [envelope.adapter.provenanceProfile]), + occurred: .dateTime(FHIRPrimitive(try DateTime(utc: recordedAt))), + recorded: FHIRPrimitive(try Instant(utc: recordedAt)), + target: targetURLs.map { Reference(reference: $0.asFHIRStringPrimitive()) } + ) + } +} + + +extension ExchangeOutputDraft.Resource { + var proxy: ResourceProxy { + switch self { + case .observation(let observation): ResourceProxy(with: observation) + case .document(let document): ResourceProxy(with: document) + } + } +} + + +extension Optional where Wrapped == [Extension] { + /// Appends `extension`, creating the array. + mutating func append(_ extension: Extension) { + self = (self ?? []) + [`extension`] + } + + /// Replaces every extension of the same url with `extension`, or appends it. + mutating func replace(_ extension: Extension) { + var extensions = self ?? [] + extensions.removeAll { $0.url == `extension`.url } + extensions.append(`extension`) + self = extensions + } +} + +// swiftlint:enable multiline_literal_brackets diff --git a/Sources/GroveFHIRContract/ExchangeGraphDraft.swift b/Sources/GroveFHIRContract/ExchangeGraphDraft.swift new file mode 100644 index 000000000..42ecd9461 --- /dev/null +++ b/Sources/GroveFHIRContract/ExchangeGraphDraft.swift @@ -0,0 +1,236 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +public import Foundation +public import ModelsR4 + + +/// What one adapter states identically in every graph it emits: its id and the profiles and clear +/// identifiers its envelope resources declare. +package struct ExchangeAdapterContract: Sendable { + package let adapterID: String + package let provenanceProfile: FHIRPrimitive + package let applicationDeviceProfile: FHIRPrimitive + /// The clear identifier an application Device carries beside its snapshot identity, when the + /// adapter's guide states one; HealthKit names the Apple bundle identifier. + package let applicationIdentifier: (@Sendable (ApplicationDevice) -> Identifier?)? + + package init( + adapterID: String, + provenanceProfile: FHIRPrimitive, + applicationDeviceProfile: FHIRPrimitive, + applicationIdentifier: (@Sendable (ApplicationDevice) -> Identifier?)? = nil + ) { + self.adapterID = adapterID + self.provenanceProfile = provenanceProfile + self.applicationDeviceProfile = applicationDeviceProfile + self.applicationIdentifier = applicationIdentifier + } +} + + +/// Everything about one producer and one source repository that is the same for every event: +/// resolved once, shared by every graph the assembler builds for them. +package struct ExchangeEnvelope: Sendable { + package let adapter: ExchangeAdapterContract + package let identityScope: OpaqueIdentityScope + package let subject: Subject + package let repositoryScope: BusinessIdentifier + package let application: ApplicationDevice + package let host: HostDevice + package let studies: [StudyEnrollment] + + package init( + adapter: ExchangeAdapterContract, + identityScope: OpaqueIdentityScope, + subject: Subject, + repositoryScope: BusinessIdentifier, + application: ApplicationDevice, + host: HostDevice, + studies: [StudyEnrollment] + ) { + self.adapter = adapter + self.identityScope = identityScope + self.subject = subject + self.repositoryScope = repositoryScope + self.application = application + self.host = host + self.studies = studies + } + + /// The source-record identity of one native record in this repository. + package func sourceRecord(sourceType: String, nativeRecordID: String) throws(OpaqueIdentityError) -> SourceRecordIdentity { + try identityScope.sourceRecord( + adapterID: adapter.adapterID, + sourceType: sourceType, + repositoryScope: repositoryScope, + nativeRecordID: nativeRecordID + ) + } +} + + +/// One output of a source record before the envelope is applied: the resource's own content, and +/// which envelope links it takes. +package struct ExchangeOutputDraft: Sendable { + /// The envelope statements an output carries beside its content. + package struct Links: OptionSet, Sendable { + /// `subject`: who the measurement is about. + package static let subject = Links(rawValue: 1 << 0) + /// `Observation.device` or `DocumentReference.author`: the recording Device when the graph has one. + package static let recordingDevice = Links(rawValue: 1 << 1) + /// The gateway-device extension when the converter role names a gateway. + package static let gateway = Links(rawValue: 1 << 2) + /// One research-study reference per bundled enrollment. + package static let studies = Links(rawValue: 1 << 3) + /// The manual-entry recording method when the record was entered by hand. + package static let manualEntry = Links(rawValue: 1 << 4) + + package static let all: Links = [.subject, .recordingDevice, .gateway, .studies, .manualEntry] + + package let rawValue: UInt8 + + package init(rawValue: UInt8) { + self.rawValue = rawValue + } + } + + package enum Resource: Sendable { + case observation(Observation) + case document(DocumentReference) + } + + /// Apple's paired sync metadata, carried as a writer-record identity and version. + package struct WriterRecord: Sendable { + package let writerApplication: String + package let syncIdentifier: String + package let version: String + + package init(writerApplication: String, syncIdentifier: String, version: String) { + self.writerApplication = writerApplication + self.syncIdentifier = syncIdentifier + self.version = version + } + } + + package let role: String + package let discriminator: String + package var resource: Resource + package var links: Links + /// Whether the primary output lists this output under `hasMember`; never set on the primary itself. + package var memberOfPrimary: Bool + /// Whether this output states the primary under `derivedFrom`; never set on the primary itself. + package var derivedFromPrimary: Bool + /// The native artifact a document output carries, named by its registered format code. + package var artifactFormatCode: String? + /// Identifiers the deployment discloses beside the opaque ones, in order. + package var clearIdentifiers: [Identifier] + package var writerRecord: WriterRecord? + package var wasUserEntered: Bool + + package init( + role: String, + discriminator: String = "single", + resource: Resource, + links: Links = .all, + memberOfPrimary: Bool = false, + derivedFromPrimary: Bool = false, + artifactFormatCode: String? = nil, + clearIdentifiers: [Identifier] = [], + writerRecord: WriterRecord? = nil, + wasUserEntered: Bool = false + ) { + self.role = role + self.discriminator = discriminator + self.resource = resource + self.links = links + self.memberOfPrimary = memberOfPrimary + self.derivedFromPrimary = derivedFromPrimary + self.artifactFormatCode = artifactFormatCode + self.clearIdentifiers = clearIdentifiers + self.writerRecord = writerRecord + self.wasUserEntered = wasUserEntered + } +} + + +/// The physical unit a record was measured on, as the adapter resolved it. +package struct ExchangeRecordingDeviceDraft: Sendable { + package let device: RecordingDevice + /// The Device body the adapter prepared from its own source facts (name, model, versions, UDI); + /// the assembler adds identity and repository id. + package var resource: Device + + package init(device: RecordingDevice, resource: Device) { + self.device = device + self.resource = resource + } +} + + +/// Who wrote the record into the source store, as the Provenance author. +package enum ExchangeWriterDraft: Sendable { + /// An application and the host it ran on, stated as snapshots of their own; `statesVersion` is + /// false when the source named no version, so the Device carries none. + case application(ApplicationDevice, host: HostDevice, statesVersion: Bool) + /// The graph's recording Device authored the record; nothing is stated without one. + case recordingDevice +} + + +/// Why a draft could not become a graph. +package enum ExchangeAssemblyError: Error, Equatable, Sendable { + /// A repository id names a node the graph does not carry. + case repositoryIDWithoutNode(ExchangeGraphNode) + /// The draft states no output. + case noOutputs + /// The source's application or host facts do not form a valid Device. + case writerInvalid +} + + +/// One assembled graph and the identities it minted, for callers that index or cross-reference them. +package struct AssembledExchangeGraph: Sendable { + package let graph: ExchangeGraph + package let identifiers: ExchangeGraphIdentifiers +} + + +/// One event's graph before assembly: the record, its outputs, and the devices and policies the +/// adapter resolved for it. +package struct ExchangeGraphDraft: Sendable { + package let event: ExchangeEventIdentifier + package let instant: Date + package let sourceRecord: SourceRecordIdentity + /// The primary output first; members and other children follow in entry order. + package var outputs: [ExchangeOutputDraft] + package var recordingDevice: ExchangeRecordingDeviceDraft? + package var writer: ExchangeWriterDraft? + package var converterRole: ConverterRole + package var repositoryIDs: [ExchangeGraphNode: RepositoryID] + + package init( + event: ExchangeEventIdentifier, + instant: Date, + sourceRecord: SourceRecordIdentity, + outputs: [ExchangeOutputDraft], + recordingDevice: ExchangeRecordingDeviceDraft? = nil, + writer: ExchangeWriterDraft? = nil, + converterRole: ConverterRole = .assembler, + repositoryIDs: [ExchangeGraphNode: RepositoryID] = [:] + ) { + self.event = event + self.instant = instant + self.sourceRecord = sourceRecord + self.outputs = outputs + self.recordingDevice = recordingDevice + self.writer = writer + self.converterRole = converterRole + self.repositoryIDs = repositoryIDs + } +} diff --git a/Sources/GroveHealthKitFHIR/HealthKitAssembly+Records.swift b/Sources/GroveHealthKitFHIR/HealthKitAssembly+Records.swift new file mode 100644 index 000000000..e7617bf4b --- /dev/null +++ b/Sources/GroveHealthKitFHIR/HealthKitAssembly+Records.swift @@ -0,0 +1,269 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +import GroveFHIRContract +import HealthKit +import ModelsR4 + + +// MARK: - Electrocardiogram + +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitAssembly { + /// Converts an already-fetched ECG and every correlated symptom as independently exchangeable + /// source events: one request per symptom, in the record's order. + func convertECG(_ record: HealthKitECGRecord, request: Request, symptomRequests: [Request]) throws -> HealthKitConversionSet { + let source = try HealthKitConverter.ecgSourceEvidence(record.electrocardiogram) + return try convertECG( + record.electrocardiogram, + evidence: HealthKitECGEvidence(source: source, waveform: try HealthKitConverter.validatedWaveform(for: record, source: source)), + symptoms: record.correlatedSymptoms, + request: request, + symptomRequests: symptomRequests + ) + } + + /// `ecg` supplies only the envelope's identity, device and source facts; the evidence is given. + func convertECG( + _ ecg: HKSample, + evidence: HealthKitECGEvidence, + symptoms: [HKCategorySample], + request: Request, + symptomRequests: [Request] + ) throws -> HealthKitConversionSet { + let companions = try symptomConversions(symptoms, source: evidence.source, symptomRequests: symptomRequests) + let input = HealthKitECGObservationInput( + source: evidence.source, + waveform: evidence.waveform, + symptomOutputIdentifiers: try validatedSymptomOutputIdentifiers(companions) + ) + guard let output = HealthKitCatalog.primaryOutput(for: .electrocardiogram) else { + throw HealthKitConversionError.unsupportedSourceType(.electrocardiogram) + } + let waveform = ExchangeOutputDraft( + role: output.role, + discriminator: output.discriminator, + resource: .observation(try HealthKitConverter.ecgObservation(input: input)) + ) + var outputs = [waveform] + if let averageHeartRate = try HealthKitConverter.ecgAverageHeartRateChild(input: input) { + outputs.append(averageHeartRate) + } + let primary = try graph(for: ecg, type: .electrocardiogram, outputs: outputs, request: request) + let events = [primary.identifiers.event] + companions.map(\.identifiers.event) + guard Set(events).count == events.count else { + throw HealthKitConversionError.ecgEvidence(.duplicateSymptomEventIdentity) + } + return HealthKitConversionSet(primary: primary, companions: companions) + } + + /// Each correlated symptom under its own event, in the deterministic order the ECG references them. + private func symptomConversions( + _ correlatedSymptoms: [HKCategorySample], + source: HealthKitECGSourceEvidence, + symptomRequests: [Request] + ) throws -> [HealthKitConversion] { + guard symptomRequests.count == correlatedSymptoms.count else { + throw HealthKitConversionError.ecgEvidence(.symptomContextCountMismatch( + symptoms: correlatedSymptoms.count, + contexts: symptomRequests.count + )) + } + let requestsBySample = Dictionary( + zip(correlatedSymptoms.map(\.uuid), symptomRequests), + uniquingKeysWith: { first, _ in first } + ) + let symptoms = try HealthKitConverter.validatedSymptomSamples(correlatedSymptoms, status: source.symptomsStatus) + return try symptoms.map { symptom in + guard let request = requestsBySample[symptom.uuid] else { + throw HealthKitConversionError.ecgEvidence(.duplicateSymptomSource(symptom.uuid)) + } + return try convert(symptom, request: request).primary + } + } + + private func validatedSymptomOutputIdentifiers(_ conversions: [HealthKitConversion]) throws -> [RoledIdentifier] { + let outputs = conversions.map(\.identifiers.primaryOutput) + let expectedSystem = envelope.identityScope.systems.opaque.sourceOutput + guard outputs.allSatisfy({ $0.role == .sourceOutput && $0.identifier.system == expectedSystem }) else { + throw HealthKitConversionError.ecgEvidence(.invalidSymptomOutputIdentity) + } + guard Set(outputs).count == outputs.count else { + throw HealthKitConversionError.ecgEvidence(.duplicateSymptomOutputIdentity) + } + return outputs + } +} + + +// MARK: - Recording documents + +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitAssembly { + /// Converts a heartbeat series into the recording document that carries its beats. + func convertHeartbeatSeries(_ record: HealthKitHeartbeatSeriesRecord, request: Request) throws -> HealthKitConversionSet { + try documentGraph( + for: record.series, + type: .heartbeatSeries, + evidence: HealthKitRecordingEvidence( + outputRole: "native-recording", + format: .beatIntervalSeries, + title: "Heartbeat series beat intervals", + payload: try HealthKitConverter.beatIntervalPayload(seriesStart: record.series.startDate, heartbeats: record.heartbeats) + ), + request: request + ) + } + + /// Converts a workout route into the recording document that carries its track, or `nil` under + /// `RouteDisclosurePolicy.omit`: omitting the route drops an addition rather than rejecting anything. + func convertWorkoutRoute(_ record: HealthKitWorkoutRouteRecord, request: Request) throws -> HealthKitConversionSet? { + guard request.options.routeDisclosure == .authorized else { + return nil + } + return try documentGraph( + for: record.route, + type: .workoutRoute, + evidence: HealthKitRecordingEvidence( + outputRole: "native-recording", + format: .locationTrackSamples, + title: "Workout route locations", + payload: try HealthKitConverter.locationTrackPayload(record.locations) + ), + request: request + ) + } + + #if !os(watchOS) + /// Carries the exact provider-issued DSTU2 or R4 JSON bytes surfaced by HealthKit in one validated + /// R4 Grove exchange graph; Grove never converts, re-encodes, or claims conformance over them. + func convertClinicalRecord(_ record: HKClinicalRecord, request: Request) throws -> HealthKitConversionSet { + guard let fhirResource = record.fhirResource else { + throw HealthKitConversionError.clinicalRecord(.empty) + } + guard let type = HealthKitSourceType(record) else { + throw HealthKitConversionError.unregisteredSourceType(record.sampleType.identifier) + } + let evidence = try HealthKitConverter.clinicalRecordingEvidence( + data: fhirResource.data, + release: fhirResource.fhirVersion.fhirRelease, + sourceTypeIdentifier: record.sampleType.identifier + ) + return try documentGraph(for: record, type: type, evidence: evidence, request: request) + } + + /// Carries a CDA document's bytes; `HKCDADocumentSample.document` is populated only by an + /// `HKDocumentQuery` that asked for document data, so any other sample fails closed. + func convertClinicalDocument(_ sample: HKCDADocumentSample, request: Request) throws -> HealthKitConversionSet { + guard let document = sample.document, let data = document.documentData, !data.isEmpty else { + throw HealthKitConversionError.clinicalRecord(.empty) + } + let title = document.title.trimmingCharacters(in: .whitespacesAndNewlines) + return try documentGraph( + for: sample, + type: .cda, + evidence: HealthKitRecordingEvidence( + outputRole: "clinical-record", + format: .clinicalDocument, + title: title.isEmpty ? "Clinical document" : title, + payload: data + ), + request: request + ) + } + #endif + + func documentGraph( + for sample: HKSample, + type: HealthKitSourceType, + evidence: HealthKitRecordingEvidence, + request: Request + ) throws -> HealthKitConversionSet { + let output = ExchangeOutputDraft( + role: evidence.outputRole, + resource: .document(try HealthKitConverter.recordingDocument(evidence: evidence, sourceTypeIdentifier: sample.sampleType.identifier)), + links: [.subject, .recordingDevice, .studies], + artifactFormatCode: evidence.format.rawValue + ) + return HealthKitConversionSet(primary: try graph(for: sample, type: type, outputs: [output], request: request)) + } +} + + +// MARK: - Retraction + +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitAssembly { + /// The complete retraction of a deleted record, as its own exchange event; every target is + /// recomputed from the record's coordinates, so nothing from its conversion needs to be kept. + func retraction( + of record: HealthKitSourceRecord, + request: Request, + occurred: RetractionOccurrence + ) throws(HealthKitConversionError) -> RetractionEvent { + let targets = try retractionTargets(of: record, request: request) + let sourceRecord = try sourceRecordIdentity(of: record) + do throws(RetractionEventError) { + return try RetractionEvent( + targets: targets, + context: eventContext(for: request), + sourceRecord: sourceRecord.identifier, + occurred: occurred + ) + } catch { + throw HealthKitConversionError(error) + } + } + + /// The logical targets a deletion retracts, named from the catalog alone: the same identity scope + /// and output roles yield the same identifiers the addition minted. The sample's UUID rides along + /// as each target's native record identifier exactly when the disclosure policy authorizes it. + func retractionTargets(of record: HealthKitSourceRecord, request: Request) throws(HealthKitConversionError) -> [RetractionTarget] { + let outputs = HealthKitCatalog.outputs(for: record.type) + guard !outputs.isEmpty else { + throw HealthKitConverter.unconvertibleSampleError(for: record.type) + } + let nativeRecordIdentifier = request.options.nativeIdentifierDisclosure.nativeRecordIdentifier( + for: record.uuid.uuidString.lowercased() + ) + let sourceRecord = try sourceRecordIdentity(of: record) + var targets: [RetractionTarget] = [] + for output in outputs { + let identity: RoledIdentifier + do { + identity = try sourceRecord.output(role: output.role, discriminator: output.discriminator) + } catch { + throw .opaqueIdentity(error) + } + do { + targets.append(try RetractionTarget( + identifier: identity, + resourceType: output.resourceType, + role: output.retractionRole, + nativeRecordIdentifier: nativeRecordIdentifier + )) + } catch { + throw .dependency(HealthKitDependencyFailure(underlying: error)) + } + } + return targets + } + + private func sourceRecordIdentity(of record: HealthKitSourceRecord) throws(HealthKitConversionError) -> SourceRecordIdentity { + do { + return try envelope.sourceRecord(sourceType: record.type.rawValue, nativeRecordID: record.uuid.uuidString.lowercased()) + } catch { + throw .opaqueIdentity(error) + } + } +} + +#endif diff --git a/Sources/GroveHealthKitFHIR/HealthKitAssembly+SourceFacts.swift b/Sources/GroveHealthKitFHIR/HealthKitAssembly+SourceFacts.swift new file mode 100644 index 000000000..415606233 --- /dev/null +++ b/Sources/GroveHealthKitFHIR/HealthKitAssembly+SourceFacts.swift @@ -0,0 +1,216 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import CoreFoundation +import Foundation +import GroveFHIRContract +import HealthKit +import ModelsR4 + + +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitAssembly { + /// What a sample says about its origin, resolved once under the policies in force: the physical + /// unit it was measured on, who wrote it, which clear identifiers travel, and what is withheld. + struct SourceFacts { + let recordingDevice: ExchangeRecordingDeviceDraft? + let writer: ExchangeWriterDraft? + let nativeIdentifiers: [Identifier] + let writerRecord: ExchangeOutputDraft.WriterRecord? + let wasUserEntered: Bool + let warnings: [HealthKitConversionWarning] + + init(_ sample: HKSample, options: HealthKitConversionOptions) throws { + let revision = sample.sourceRevision + let metadata = sample.metadata + var warnings: [HealthKitConversionWarning] = [] + var recordingDevice: ExchangeRecordingDeviceDraft? + if let healthKitDevice = sample.device { + if let recorder = options.recordingDevice.recordingDevice(for: healthKitDevice) { + recordingDevice = Self.recordingDevice(recorder, healthKitDevice: healthKitDevice, udi: options.udiDisclosure) + } else { + // Model and version facts cannot identify a physical unit, so the shared recording + // Device is omitted rather than merged, and the omission is reported. + warnings.append(.recordingDeviceOmitted(deviceName: healthKitDevice.name?.nonBlank)) + } + } + if recordingDevice == nil, options.writer == .device { + recordingDevice = Self.recordingDevice(fromAppleSource: revision) + } + self.recordingDevice = recordingDevice + self.writer = try Self.writer(revision, classification: options.writer) + self.nativeIdentifiers = [options.nativeIdentifierDisclosure.identifier(for: sample.uuid.uuidString.lowercased())].compactMap(\.self) + self.writerRecord = try Self.writerRecord(metadata: metadata, writerApplication: revision.source.bundleIdentifier) + self.wasUserEntered = (metadata?[HKMetadataKeyWasUserEntered] as? Bool) == true + let unmodeled = (metadata ?? [:]).keys.filter { !HealthKitMetadataField.keys.contains($0) }.sorted() + if !unmodeled.isEmpty { + warnings.append(.unmodeledMetadataWithheld(keys: unmodeled)) + } + self.warnings = warnings + } + } +} + + +// MARK: - Recording device + +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitAssembly.SourceFacts { + /// The resolved physical unit with the facts its `HKDevice` states about it. + private static func recordingDevice( + _ recorder: RecordingDevice, + healthKitDevice: HKDevice, + udi: HealthKitUDIDisclosurePolicy + ) -> ExchangeRecordingDeviceDraft { + var device = recordingDevice( + name: recorder.name ?? healthKitDevice.name?.nonBlank, + manufacturer: recorder.manufacturer ?? healthKitDevice.manufacturer?.nonBlank, + modelNumber: recorder.modelNumber ?? healthKitDevice.model?.nonBlank + ) + var versions: [DeviceVersion] = [] + versions.appendVersion(healthKitDevice.hardwareVersion, code: "531974", display: "MDC_ID_PROD_SPEC_HW") + versions.appendVersion(healthKitDevice.firmwareVersion, code: "531976", display: "MDC_ID_PROD_SPEC_FW") + versions.appendVersion(healthKitDevice.softwareVersion, code: "531975", display: "MDC_ID_PROD_SPEC_SW") + device.version = versions.isEmpty ? nil : versions + if udi == .authorizedUDI, let udi = healthKitDevice.udiDeviceIdentifier?.nonBlank { + device.udiCarrier = [DeviceUdiCarrier(deviceIdentifier: udi.asFHIRStringPrimitive())] + } + return ExchangeRecordingDeviceDraft(device: recorder, resource: device) + } + + /// The physical unit an Apple per-device source stands for, when the sample carries no `HKDevice` + /// with a stable token: the source's per-device bundle identifier is that token. Any other source + /// yields nothing; its manufacturer and model are not known. + private static func recordingDevice(fromAppleSource revision: HKSourceRevision) -> ExchangeRecordingDeviceDraft? { + let bundleIdentifier = revision.source.bundleIdentifier + guard bundleIdentifier.hasPrefix(HealthKitConverter.appleDeviceSourcePrefix), + let recorder = try? RecordingDevice( + stableUnitToken: bundleIdentifier, + name: revision.source.name.nonBlank, + manufacturer: "Apple Inc.", + modelNumber: revision.productType?.nonBlank + ) else { + return nil + } + return ExchangeRecordingDeviceDraft( + device: recorder, + resource: recordingDevice(name: recorder.name, manufacturer: recorder.manufacturer, modelNumber: recorder.modelNumber) + ) + } + + private static func recordingDevice(name: String?, manufacturer: String?, modelNumber: String?) -> Device { + var device = Device() + device.meta = Meta(profile: [Profile.groveRecordingDevice]) + device.status = FHIRPrimitive(.active) + if let name { + device.deviceName = [DeviceDeviceName(name: name.asFHIRStringPrimitive(), type: FHIRPrimitive(.userFriendlyName))] + } + device.manufacturer = manufacturer?.asFHIRStringPrimitive() + device.modelNumber = modelNumber?.asFHIRStringPrimitive() + return device + } +} + + +// MARK: - Writer + +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitAssembly.SourceFacts { + private static func writer(_ revision: HKSourceRevision, classification: HealthKitWriter) throws -> ExchangeWriterDraft? { + switch classification { + case .omit: + return nil + case .device: + return .recordingDevice + case .application: + guard let name = revision.source.name.nonBlank, + let bundleIdentifier = revision.source.bundleIdentifier.nonBlank else { + return nil + } + let version = revision.version?.nonBlank + do { + return .application( + try ApplicationDevice(name: name, bundleIdentifier: bundleIdentifier, version: version ?? "unknown"), + host: try HostDevice( + operatingSystemVersion: operatingSystemVersion(revision.operatingSystemVersion), + modelNumber: revision.productType?.nonBlank + ), + statesVersion: version != nil + ) + } catch { + throw HealthKitConversionError.sourceApplicationInvalid + } + } + } + + private static func operatingSystemVersion(_ version: OperatingSystemVersion) -> String { + "\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)" + } +} + + +// MARK: - Writer record + +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitAssembly.SourceFacts { + // HealthKit itself models the metadata dictionary as absent when an object has no metadata. + /// Apple's paired sync metadata, validated independently of source attribution. A valid pair + /// without an attributable writer stays omitted rather than being assigned to an invented writer. + static func writerRecord( + metadata: [String: Any]?, // swiftlint:disable:this discouraged_optional_collection + writerApplication: String + ) throws -> ExchangeOutputDraft.WriterRecord? { + let identifierValue = metadata?[HKMetadataKeySyncIdentifier] + let versionValue = metadata?[HKMetadataKeySyncVersion] + guard identifierValue != nil || versionValue != nil else { + return nil + } + guard let syncIdentifier = identifierValue as? String, !syncIdentifier.isEmpty else { + throw HealthKitValueFailure.invalidMetadataValue(.syncIdentifier) + } + guard let versionValue else { + throw HealthKitValueFailure.invalidMetadataValue(.syncVersion) + } + let version = try canonicalSyncVersion(versionValue) + guard !writerApplication.isEmpty else { + return nil + } + return ExchangeOutputDraft.WriterRecord(writerApplication: writerApplication, syncIdentifier: syncIdentifier, version: version) + } + + private static func canonicalSyncVersion(_ value: Any) throws -> String { + guard let number = value as? NSNumber, + CFGetTypeID(number) != CFBooleanGetTypeID(), + var decimal = Decimal(string: number.stringValue, locale: Locale(identifier: "en_US_POSIX")), + !decimal.isNaN, + decimal >= 0 else { + throw HealthKitValueFailure.invalidMetadataValue(.syncVersion) + } + var integral = Decimal() + NSDecimalRound(&integral, &decimal, 0, .down) + guard integral == decimal else { + throw HealthKitValueFailure.invalidMetadataValue(.syncVersion) + } + return NSDecimalString(&integral, Locale(identifier: "en_US_POSIX")) + } +} + + +extension Array where Element == DeviceVersion { + fileprivate mutating func appendVersion(_ value: String?, code: String, display: String) { + guard let value = value?.nonBlank else { + return + } + let type = Coding(code: code.asFHIRStringPrimitive(), display: display.asFHIRStringPrimitive(), system: Canonicals.mdc) + append(DeviceVersion(type: CodeableConcept(coding: [type]), value: value.asFHIRStringPrimitive())) + } +} + +#endif diff --git a/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift b/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift new file mode 100644 index 000000000..155557754 --- /dev/null +++ b/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift @@ -0,0 +1,197 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +import GroveFHIRContract +import HealthKit +import ModelsR4 + + +/// The HealthKit adapter's graph assembly for one producer and one HealthKit store. +/// +/// It turns a sample into the outputs its catalog contract names, resolves what the sample says about +/// its writer and recording device, and hands the draft to the shared ``ExchangeGraphAssembler``. +@available(iOS 18, macOS 15, watchOS 11, *) +struct HealthKitAssembly: Sendable { + /// What one record's conversion needs beyond the envelope: its event, and the policies in force. + struct Request: Sendable { + let event: ExchangeEventIdentifier + let instant: Date + let converterRole: ConverterRole + let repositoryIDs: [ExchangeGraphNode: RepositoryID] + let options: HealthKitConversionOptions + + init( + event: ExchangeEventIdentifier, + instant: Date, + converterRole: ConverterRole = .assembler, + repositoryIDs: [ExchangeGraphNode: RepositoryID] = [:], + options: HealthKitConversionOptions = .default + ) { + self.event = event + self.instant = instant + self.converterRole = converterRole + self.repositoryIDs = repositoryIDs + self.options = options + } + + init(context: HealthKitConversionContext) { + self.init( + event: context.event.event, + instant: context.event.conversionInstant, + converterRole: context.event.converterRole, + repositoryIDs: context.event.repositoryIDs, + options: context.options + ) + } + } + + static let adapter = ExchangeAdapterContract( + adapterID: "healthkit", + provenanceProfile: HealthKitContract.conversionProvenanceProfile, + applicationDeviceProfile: HealthKitContract.applicationDeviceProfile + ) { application in + let type = Coding( + code: HealthKitContract.appleBundleIdentifierTypeCode.asFHIRStringPrimitive(), + system: HealthKitContract.appleBundleIdentifierTypeSystem + ) + return Identifier( + system: HealthKitContract.appleBundleIdentifierSystem, + type: CodeableConcept(coding: [type]), + value: application.bundleIdentifier.asFHIRStringPrimitive() + ) + } + + let assembler: ExchangeGraphAssembler + + var envelope: ExchangeEnvelope { assembler.envelope } + + init(envelope: ExchangeEnvelope) { + self.assembler = ExchangeGraphAssembler(envelope: envelope) + } + + init(context: ExchangeEventContext) { + self.init(envelope: ExchangeEnvelope( + adapter: Self.adapter, + identityScope: context.identityScope, + subject: context.subject, + repositoryScope: context.repositoryScope, + application: context.application, + host: context.host, + studies: context.studies + )) + } + + /// Converts one sample only when the closed catalog admits its exact published contract. + func convert(_ sample: HKSample, request: Request) throws -> HealthKitConversionSet { + guard let type = HealthKitSourceType(sample) else { + throw HealthKitConversionError.unregisteredSourceType(sample.sampleType.identifier) + } + if sample is HKElectrocardiogram { + throw HealthKitConversionError.ecgEvidence(.evidenceRequired) + } + #if !os(watchOS) + if let record = sample as? HKClinicalRecord { + return try convertClinicalRecord(record, request: request) + } + if let document = sample as? HKCDADocumentSample { + return try convertClinicalDocument(document, request: request) + } + #endif + guard let binding = HealthKitCatalog.binding(for: sample), + let output = HealthKitCatalog.primaryOutput(for: type) else { + throw HealthKitConverter.unconvertibleSampleError(for: type) + } + let primary = ExchangeOutputDraft( + role: output.role, + discriminator: output.discriminator, + resource: .observation(try HealthKitConverter.observation(for: sample, binding: binding)) + ) + var outputs = [primary] + if let workout = sample as? HKWorkout { + outputs += try HealthKitConverter.workoutSegments(workout) + } + return HealthKitConversionSet(primary: try graph(for: sample, type: type, outputs: outputs, request: request)) + } + + /// One source record's graph: the outputs under the sample's envelope, with what the graph does not carry. + func graph( + for sample: HKSample, + type: HealthKitSourceType, + outputs: [ExchangeOutputDraft], + request: Request + ) throws -> HealthKitConversion { + let source = HealthKitSourceRecord(uuid: sample.uuid, type: type) + let facts = try SourceFacts(sample, options: request.options) + var outputs = outputs + outputs[0].clearIdentifiers = facts.nativeIdentifiers + outputs[0].writerRecord = facts.writerRecord + outputs[0].wasUserEntered = facts.wasUserEntered + let draft = ExchangeGraphDraft( + event: request.event, + instant: request.instant, + sourceRecord: try envelope.sourceRecord(sourceType: type.rawValue, nativeRecordID: sample.uuid.uuidString.lowercased()), + outputs: outputs, + recordingDevice: facts.recordingDevice, + writer: facts.writer, + converterRole: request.converterRole, + repositoryIDs: request.repositoryIDs + ) + let assembled = try assembler.assemble(draft) + return HealthKitConversion( + source: source, + identifiers: assembled.identifiers, + graph: assembled.graph, + warnings: facts.warnings + sourceOffsetWarnings(for: sample, outputs: outputs) + ) + } + + /// The effective elements the outputs serialized in UTC because the sample named no time zone, each once. + private func sourceOffsetWarnings(for sample: HKSample, outputs: [ExchangeOutputDraft]) -> [HealthKitConversionWarning] { + guard sample.metadata?[HKMetadataKeyTimeZone] == nil else { + return [] + } + var fields: [String] = [] + for output in outputs { + guard case .observation(let observation) = output.resource else { + continue + } + let elements = switch observation.effective { + case .dateTime: ["Observation.effectiveDateTime"] + case .period: ["Observation.effectivePeriod.start", "Observation.effectivePeriod.end"] + case .instant, .timing, nil: [String]() + } + fields += elements.filter { !fields.contains($0) } + } + return fields.map { .sourceOffsetUnavailable(field: $0) } + } +} + + +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitAssembly { + /// The event context a retraction or a bundled study context is minted from. + func eventContext(for request: Request) -> ExchangeEventContext { + ExchangeEventContext( + subject: envelope.subject, + event: request.event, + identityScope: envelope.identityScope, + repositoryScope: envelope.repositoryScope, + application: envelope.application, + host: envelope.host, + conversionInstant: request.instant, + converterRole: request.converterRole, + studies: envelope.studies, + repositoryIDs: request.repositoryIDs + ) + } +} + +#endif diff --git a/Sources/GroveHealthKitFHIR/HealthKitConversionError.swift b/Sources/GroveHealthKitFHIR/HealthKitConversionError.swift index 0f6a6a198..2e5240211 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConversionError.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConversionError.swift @@ -250,6 +250,10 @@ extension HealthKitConversionError { self = .opaqueIdentity(error) case let error as ExchangeGraphError: self = .exchangeGraph(error) + case .repositoryIDWithoutNode(let node) as ExchangeAssemblyError: + self = .repositoryIDWithoutNode(node) + case ExchangeAssemblyError.writerInvalid: + self = .sourceApplicationInvalid default: self = .dependency(HealthKitDependencyFailure(underlying: error)) } diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+ClinicalDocument.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+ClinicalDocument.swift index e803b5ce5..36e865ffb 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+ClinicalDocument.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter+ClinicalDocument.swift @@ -30,27 +30,13 @@ extension HealthKitConverter { context: HealthKitConversionContext ) throws(HealthKitConversionError) -> HealthKitConversionSet { do { - return try Self.convertClinicalRecord(record, context: context) + try Self.validate(context: context) + return try HealthKitAssembly(context: context.event).convertClinicalRecord(record, request: .init(context: context)) } catch { throw HealthKitConversionError(conversionFailure: error, source: HealthKitSourceType(record)) } } - static func convertClinicalRecord( - _ record: HKClinicalRecord, - context: HealthKitConversionContext - ) throws -> HealthKitConversionSet { - guard let fhirResource = record.fhirResource else { - throw HealthKitConversionError.clinicalRecord(.empty) - } - let evidence = try clinicalRecordingEvidence( - data: fhirResource.data, - release: fhirResource.fhirVersion.fhirRelease, - sourceTypeIdentifier: record.sampleType.identifier - ) - return try assembleDocumentGraph(for: record, evidence: evidence, context: context) - } - static func clinicalRecordingEvidence( data: Data, release: HKFHIRRelease, @@ -104,34 +90,13 @@ extension HealthKitConverter { context: HealthKitConversionContext ) throws(HealthKitConversionError) -> HealthKitConversionSet { do { - return try Self.convertClinicalDocument(sample, context: context) + try Self.validate(context: context) + return try HealthKitAssembly(context: context.event).convertClinicalDocument(sample, request: .init(context: context)) } catch { throw HealthKitConversionError(conversionFailure: error, source: .cda) } } - static func convertClinicalDocument( - _ sample: HKCDADocumentSample, - context: HealthKitConversionContext - ) throws -> HealthKitConversionSet { - guard let document = sample.document, - let data = document.documentData, - !data.isEmpty else { - throw HealthKitConversionError.clinicalRecord(.empty) - } - let title = document.title.trimmingCharacters(in: .whitespacesAndNewlines) - return try assembleDocumentGraph( - for: sample, - evidence: HealthKitRecordingEvidence( - outputRole: "clinical-record", - format: .clinicalDocument, - title: title.isEmpty ? "Clinical document" : title, - payload: data - ), - context: context - ) - } - private static func clinicalRecordTypeCode( sourceTypeIdentifier: String ) throws(HealthKitConversionError) -> String { diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+Devices.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+Devices.swift deleted file mode 100644 index 0de3e6efb..000000000 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+Devices.swift +++ /dev/null @@ -1,334 +0,0 @@ -// -// This source file is part of the Grove open-source project -// -// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) -// -// SPDX-License-Identifier: MIT -// - -// Device and Provenance literals follow the FHIR resource shape they build. -// swiftlint:disable multiline_literal_brackets - -#if canImport(HealthKit) - -import FHIRModelsExtensions -import Foundation -import GroveFHIRContract -import GroveHealthKit -import HealthKit -import ModelsR4 - - -@available(iOS 18, macOS 15, watchOS 11, *) -extension HealthKitConverter { - struct ResolvedRecordingDevice { - let device: IdentifiedDevice? - let warning: HealthKitConversionWarning? - } - - static func applicationDevice(_ application: ApplicationDevice) -> Device { - var device = Device() - device.meta = Meta(profile: [HealthKitContract.applicationDeviceProfile]) - device.status = FHIRPrimitive(.active) - device.identifier = [Identifier( - system: HealthKitContract.appleBundleIdentifierSystem, - type: CodeableConcept(coding: [Coding( - code: HealthKitContract.appleBundleIdentifierTypeCode.asFHIRStringPrimitive(), - system: HealthKitContract.appleBundleIdentifierTypeSystem - )]), - value: application.bundleIdentifier.asFHIRStringPrimitive() - )] - device.deviceName = [DeviceDeviceName( - name: application.name.asFHIRStringPrimitive(), - type: FHIRPrimitive(.userFriendlyName) - )] - device.version = [DeviceVersion( - type: CodeableConcept(coding: [Coding( - code: "531975", - display: "MDC_ID_PROD_SPEC_SW", - system: Canonicals.mdc - )]), - value: application.version.asFHIRStringPrimitive() - )] - if let build = application.build { - device.version?.append(groveVersion("build", "Build", build)) - } - // The operating-system version is a host snapshot fact, not application software. - return device - } - - static func hostDevice(_ host: HostDevice) -> Device { - var device = Device() - device.meta = Meta(profile: [Profile.groveHostDevice]) - device.status = FHIRPrimitive(.active) - if let name = host.name { - device.deviceName = [DeviceDeviceName( - name: name.asFHIRStringPrimitive(), - type: FHIRPrimitive(.userFriendlyName) - )] - } - device.manufacturer = host.manufacturer?.asFHIRStringPrimitive() - device.modelNumber = host.modelNumber?.asFHIRStringPrimitive() - device.version = [groveVersion( - "os-version", - "Operating system version", - host.operatingSystemVersion - )] - return device - } - - private static func groveVersion(_ code: String, _ display: String, _ value: String) -> DeviceVersion { - DeviceVersion( - type: CodeableConcept(coding: [Coding( - code: code.asFHIRStringPrimitive(), - display: display.asFHIRStringPrimitive(), - system: Canonicals.groveApplicationVersionType - )]), - value: value.asFHIRStringPrimitive() - ) - } - - /// The application snapshot the converter states about itself, or about a distinct gateway application. - static func applicationSnapshot( - _ application: ApplicationDevice, - parentURL: String?, - repositoryID: RepositoryID?, - context: HealthKitConversionContext - ) throws -> IdentifiedDevice { - let identity = try context.identityScope.deviceSnapshot( - event: context.eventIdentifier, - role: .application, - sourceDeviceToken: application.sourceDeviceToken - ) - var resource = applicationDevice(application) - resource.id = repositoryID?.primitive - resource.identifier = [identity.fhirIdentifier] + (resource.identifier ?? []) - resource.parent = parentURL.map { Reference(reference: $0.asFHIRStringPrimitive()) } - return IdentifiedDevice(resource: resource, identity: identity) - } - - static func hostSnapshot( - _ host: HostDevice, - repositoryID: RepositoryID?, - context: HealthKitConversionContext - ) throws -> IdentifiedDevice { - let identity = try context.identityScope.deviceSnapshot( - event: context.eventIdentifier, - role: .host, - sourceDeviceToken: host.sourceDeviceToken - ) - var resource = hostDevice(host) - resource.id = repositoryID?.primitive - resource.identifier = [identity.fhirIdentifier] - return IdentifiedDevice(resource: resource, identity: identity) - } - - static func recordingDevice( - for healthKitDevice: HKDevice?, - context: HealthKitConversionContext - ) throws -> ResolvedRecordingDevice { - guard let healthKitDevice else { - return ResolvedRecordingDevice(device: nil, warning: nil) - } - guard let recorder = context.options.recordingDevice.recordingDevice(for: healthKitDevice) else { - // Model and version facts cannot identify a physical unit, so the shared recording - // Device is omitted rather than merged, and the omission is reported. - return ResolvedRecordingDevice( - device: nil, - warning: .recordingDeviceOmitted(deviceName: healthKitDevice.name?.nonBlank) - ) - } - return try recordingDeviceSnapshot(recorder: recorder, healthKitDevice: healthKitDevice, context: context) - } - - /// The physical unit an Apple per-device source stands for, when the sample carries no `HKDevice` - /// with a stable token: the source's per-device bundle identifier is that token. Any other source - /// yields nothing, exactly as before; its manufacturer and model are not known. - static func recordingDevice( - fromSource revision: HKSourceRevision, - context: HealthKitConversionContext - ) throws -> ResolvedRecordingDevice { - let bundleIdentifier = revision.source.bundleIdentifier - guard bundleIdentifier.hasPrefix(appleDeviceSourcePrefix), - let recorder = try? RecordingDevice( - stableUnitToken: bundleIdentifier, - name: revision.source.name.nonBlank, - manufacturer: "Apple Inc.", - modelNumber: revision.productType?.nonBlank - ) else { - return ResolvedRecordingDevice(device: nil, warning: nil) - } - return try recordingDeviceSnapshot(recorder: recorder, healthKitDevice: nil, context: context) - } - - private static func recordingDeviceSnapshot( - recorder: RecordingDevice, - healthKitDevice: HKDevice?, - context: HealthKitConversionContext - ) throws -> ResolvedRecordingDevice { - var device = Device() - device.meta = Meta(profile: [Profile.groveRecordingDevice]) - device.status = FHIRPrimitive(.active) - device.id = context.repositoryID(.recordingDevice)?.primitive - if let name = recorder.name ?? healthKitDevice?.name?.nonBlank { - device.deviceName = [DeviceDeviceName( - name: name.asFHIRStringPrimitive(), - type: FHIRPrimitive(.userFriendlyName) - )] - } - device.manufacturer = (recorder.manufacturer ?? healthKitDevice?.manufacturer?.nonBlank)?.asFHIRStringPrimitive() - device.modelNumber = (recorder.modelNumber ?? healthKitDevice?.model?.nonBlank)?.asFHIRStringPrimitive() - var versions: [DeviceVersion] = [] - versions.appendVersion(healthKitDevice?.hardwareVersion, code: "531974", display: "MDC_ID_PROD_SPEC_HW") - versions.appendVersion(healthKitDevice?.firmwareVersion, code: "531976", display: "MDC_ID_PROD_SPEC_FW") - versions.appendVersion(healthKitDevice?.softwareVersion, code: "531975", display: "MDC_ID_PROD_SPEC_SW") - device.version = versions.isEmpty ? nil : versions - - if context.options.udiDisclosure == .authorizedUDI, - let udi = healthKitDevice?.udiDeviceIdentifier?.nonBlank { - device.udiCarrier = [DeviceUdiCarrier(deviceIdentifier: udi.asFHIRStringPrimitive())] - } - let stableIdentity = try context.identityScope.recordingDevice( - adapterID: HealthKitConverter.adapterID, - subject: context.subjectIdentifier, - stableUnitToken: recorder.stableUnitToken - ) - let snapshotIdentity = try context.identityScope.deviceSnapshot( - event: context.eventIdentifier, - role: .recordingDevice, - sourceDeviceToken: recorder.stableUnitToken - ) - device.identifier = [snapshotIdentity.fhirIdentifier, stableIdentity.fhirIdentifier] - return ResolvedRecordingDevice( - device: IdentifiedDevice(resource: device, identity: snapshotIdentity), - warning: nil - ) - } - - static func writer( - for revision: HKSourceRevision, - classification: HealthKitWriter, - context: HealthKitConversionContext - ) throws -> WriterDevices? { - switch classification { - case .application: - return try writerApplication(for: revision, context: context) - case .device: - // The graph envelope reuses its recording Device as the writer. A second Device keyed - // from application, model, or record identifiers would falsely claim a physical unit. - return nil - case .omit: - return nil - } - } - - private static func writerApplication( - for revision: HKSourceRevision, - context: HealthKitConversionContext - ) throws -> WriterDevices? { - guard let name = revision.source.name.nonBlank, - let bundleIdentifier = revision.source.bundleIdentifier.nonBlank else { - return nil - } - let application: ApplicationDevice - let host: HostDevice - do { - application = try ApplicationDevice( - name: name, - bundleIdentifier: bundleIdentifier, - version: revision.version?.nonBlank ?? "unknown" - ) - host = try HostDevice( - operatingSystemVersion: operatingSystemVersion(revision.operatingSystemVersion), - modelNumber: revision.productType?.nonBlank - ) - } catch { - throw HealthKitConversionError.sourceApplicationInvalid - } - let hostSnapshot = try hostSnapshot(host, repositoryID: context.repositoryID(.writerHost), context: context) - let hostURL = try hostSnapshot.identity.fullURLString - let identity = try context.identityScope.deviceSnapshot( - event: context.eventIdentifier, - role: .application, - sourceDeviceToken: application.sourceDeviceToken - ) - var device = applicationDevice(application) - if revision.version?.nonBlank == nil { - device.version = nil - } - device.id = context.repositoryID(.writer)?.primitive - device.identifier = [identity.fhirIdentifier] + (device.identifier ?? []) - device.parent = Reference(reference: hostURL.asFHIRStringPrimitive()) - return WriterDevices( - application: IdentifiedDevice(resource: device, identity: identity), - host: hostSnapshot - ) - } - - private static func operatingSystemVersion(_ version: OperatingSystemVersion) -> String { - "\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)" - } - - static func provenance( - sourceIdentifier: Identifier, - targetURL: String, - converterURL: String, - writerURL: String?, - recordedAt: Date - ) throws -> Provenance { - let writer = writerURL.map { url in - ProvenanceAgent( - type: CodeableConcept(coding: [Coding( - code: "author", - display: "Author", - system: Canonicals.provenanceParticipantType - )]), - who: Reference(reference: url.asFHIRStringPrimitive()) - ) - } - var entity = ProvenanceEntity( - role: FHIRPrimitive(.source), - what: Reference(identifier: sourceIdentifier) - ) - entity.agent = writer.map { [$0] } - return Provenance( - activity: CodeableConcept(coding: [Coding( - code: "transform", - display: "Transform/Translate Record Lifecycle Event", - system: Canonicals.isoLifecycleEvent - )]), - agent: [ProvenanceAgent( - type: CodeableConcept(coding: [Coding( - code: "assembler", - display: "Assembler", - system: Canonicals.provenanceParticipantType - )]), - who: Reference(reference: converterURL.asFHIRStringPrimitive()) - )], - entity: [entity], - meta: Meta(profile: [HealthKitContract.conversionProvenanceProfile]), - occurred: .dateTime(FHIRPrimitive(try DateTime(utc: recordedAt))), - recorded: FHIRPrimitive(try Instant(utc: recordedAt)), - target: [Reference(reference: targetURL.asFHIRStringPrimitive())] - ) - } -} - - -extension Array where Element == DeviceVersion { - fileprivate mutating func appendVersion(_ value: String?, code: String, display: String) { - guard let value = value?.nonBlank else { - return - } - append(DeviceVersion( - type: CodeableConcept(coding: [Coding( - code: code.asFHIRStringPrimitive(), - display: display.asFHIRStringPrimitive(), - system: Canonicals.mdc - )]), - value: value.asFHIRStringPrimitive() - )) - } -} - -#endif diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+ECG.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+ECG.swift index 4d9064425..482d3b0ea 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+ECG.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter+ECG.swift @@ -31,7 +31,15 @@ extension HealthKitConverter { symptomContexts: [HealthKitConversionContext] ) throws(HealthKitConversionError) -> HealthKitConversionSet { do { - return try Self.convertECG(record, context: context, symptomContexts: symptomContexts) + try Self.validate(context: context) + for symptomContext in symptomContexts { + try Self.validateSymptomConversionContext(symptomContext, expectedContext: context) + } + return try HealthKitAssembly(context: context.event).convertECG( + record, + request: .init(context: context), + symptomRequests: symptomContexts.map { .init(context: $0) } + ) } catch { throw HealthKitConversionError(conversionFailure: error, source: .electrocardiogram) } @@ -41,12 +49,24 @@ extension HealthKitConverter { @available(iOS 18, macOS 15, watchOS 11, *) extension HealthKitConverter { + /// A companion belongs to the same subject, repository scope and identity scope as the ECG. + static func validateSymptomConversionContext( + _ symptomContext: HealthKitConversionContext, + expectedContext: HealthKitConversionContext + ) throws { + guard symptomContext.event.subject == expectedContext.event.subject, + symptomContext.repositoryScope == expectedContext.repositoryScope, + symptomContext.identityScope.systems == expectedContext.identityScope.systems, + symptomContext.identityScope.keyID == expectedContext.identityScope.keyID, + symptomContext.identityScope.epoch == expectedContext.identityScope.epoch else { + throw HealthKitConversionError.ecgEvidence(.mismatchedSymptomContext) + } + } + static func averageHeartRateObservation( value: Double, - identity: RoledIdentifier, effective: Period, - input: HealthKitECGObservationInput, - envelope: GraphEnvelope + input: HealthKitECGObservationInput ) throws -> Observation { var observation = Observation( code: CodeableConcept(coding: [ @@ -72,25 +92,12 @@ extension HealthKitConverter { Profile.groveMobileHeartRate, Profile.healthkitEcgAverageHeartRateObservation ]) - observation.identifier = [ - envelope.sourceRecord.identifier.fhirIdentifier, - identity.fhirIdentifier - ] - observation.subject = envelope.graphContext.subject observation.effective = .period(effective) observation.value = .quantity(try decimalQuantity( value, code: "/min", display: "beats/minute" )) - observation.derivedFrom = [ - Reference(reference: envelope.primaryURL.asFHIRStringPrimitive()) - ] - applyGraphContext( - to: &observation, - graphContext: envelope.graphContext, - wasUserEntered: input.source.wasUserEntered - ) return observation } diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+ECGCore.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+ECGCore.swift index 64a4345b0..584f06558 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+ECGCore.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter+ECGCore.swift @@ -17,128 +17,7 @@ import ModelsR4 @available(iOS 18, macOS 15, watchOS 11, *) extension HealthKitConverter { - static func convertECG( - _ record: HealthKitECGRecord, - context: HealthKitConversionContext, - symptomContexts: [HealthKitConversionContext] - ) throws -> HealthKitConversionSet { - try validate(context: context) - let source = try ecgSourceEvidence(record.electrocardiogram) - return try convertECG( - record.electrocardiogram, - evidence: HealthKitECGEvidence(source: source, waveform: try validatedWaveform(for: record, source: source)), - symptoms: record.correlatedSymptoms, - context: context, - symptomContexts: symptomContexts - ) - } - - /// `ecg` supplies only the graph envelope's identity, device and source evidence. - static func convertECG( - _ ecg: HKSample, - evidence: HealthKitECGEvidence, - symptoms: [HKCategorySample], - context: HealthKitConversionContext, - symptomContexts: [HealthKitConversionContext] - ) throws -> HealthKitConversionSet { - let symptomConversions = try symptomConversions( - symptoms, - source: evidence.source, - context: context, - symptomContexts: symptomContexts - ) - let input = HealthKitECGObservationInput( - source: evidence.source, - waveform: evidence.waveform, - symptomOutputIdentifiers: try validatedSymptomOutputIdentifiers( - symptomConversions, - expectedSystem: context.identityScope.systems.opaque.sourceOutput - ) - ) - guard let output = HealthKitCatalog.primaryOutput(for: .electrocardiogram) else { - throw HealthKitConversionError.unsupportedSourceType(.electrocardiogram) - } - let primary = try assembleGraph( - for: ecg, - context: context, - outputRole: output.role, - outputDiscriminator: output.discriminator, - childBuilder: { envelope in - try ecgAverageHeartRateChild(input: input, envelope: envelope).map { [$0] } ?? [] - } - ) { graphContext in - try ecgObservation(input: input, graphContext: graphContext) - } - let events = [primary.primary.identifiers.event] + symptomConversions.map(\.identifiers.event) - guard Set(events).count == events.count else { - throw HealthKitConversionError.ecgEvidence(.duplicateSymptomEventIdentity) - } - guard !input.symptomOutputIdentifiers.contains(primary.primary.identifiers.primaryOutput) else { - throw HealthKitConversionError.ecgEvidence(.invalidSymptomOutputIdentity) - } - return HealthKitConversionSet(primary: primary.primary, companions: symptomConversions) - } - - /// Converts each correlated symptom under its own event context, in the deterministic order the - /// ECG references them. - private static func symptomConversions( - _ correlatedSymptoms: [HKCategorySample], - source: HealthKitECGSourceEvidence, - context: HealthKitConversionContext, - symptomContexts: [HealthKitConversionContext] - ) throws -> [HealthKitConversion] { - guard symptomContexts.count == correlatedSymptoms.count else { - throw HealthKitConversionError.ecgEvidence(.symptomContextCountMismatch( - symptoms: correlatedSymptoms.count, - contexts: symptomContexts.count - )) - } - let contextsBySample = Dictionary( - correlatedSymptoms.map(\.uuid).enumerated().map { ($1, symptomContexts[$0]) }, - uniquingKeysWith: { first, _ in first } - ) - let symptoms = try validatedSymptomSamples(correlatedSymptoms, status: source.symptomsStatus) - return try symptoms.map { symptom in - guard let symptomContext = contextsBySample[symptom.uuid] else { - throw HealthKitConversionError.ecgEvidence(.duplicateSymptomSource(symptom.uuid)) - } - try validateSymptomConversionContext(symptomContext, expectedContext: context) - let set = try convertSample(symptom, context: symptomContext) - return set.primary - } - } - - /// A companion belongs to the same subject, repository scope and identity scope as the ECG. - static func validateSymptomConversionContext( - _ symptomContext: HealthKitConversionContext, - expectedContext: HealthKitConversionContext - ) throws { - guard symptomContext.event.subject == expectedContext.event.subject, - symptomContext.repositoryScope == expectedContext.repositoryScope, - symptomContext.identityScope.systems == expectedContext.identityScope.systems, - symptomContext.identityScope.keyID == expectedContext.identityScope.keyID, - symptomContext.identityScope.epoch == expectedContext.identityScope.epoch else { - throw HealthKitConversionError.ecgEvidence(.mismatchedSymptomContext) - } - } - - private static func validatedSymptomOutputIdentifiers( - _ conversions: [HealthKitConversion], - expectedSystem: IdentifierSystem - ) throws -> [RoledIdentifier] { - let outputs = conversions.map(\.identifiers.primaryOutput) - guard outputs.allSatisfy({ - $0.role == .sourceOutput && $0.identifier.system == expectedSystem - }) else { - throw HealthKitConversionError.ecgEvidence(.invalidSymptomOutputIdentity) - } - guard Set(outputs).count == outputs.count else { - throw HealthKitConversionError.ecgEvidence(.duplicateSymptomOutputIdentity) - } - return outputs - } - - private static func validatedWaveform( + static func validatedWaveform( for record: HealthKitECGRecord, source: HealthKitECGSourceEvidence ) throws -> HealthKitECGValidatedWaveform { @@ -158,7 +37,7 @@ extension HealthKitConverter { ) } - private static func ecgSourceEvidence( + static func ecgSourceEvidence( _ ecg: HKElectrocardiogram ) throws -> HealthKitECGSourceEvidence { HealthKitECGSourceEvidence( @@ -176,10 +55,9 @@ extension HealthKitConverter { ) } - static func ecgObservation( - input: HealthKitECGObservationInput, - graphContext: HealthKitGraphContext - ) throws -> Observation { + /// The ECG Observation content; symptoms are referenced by identifier because they travel as + /// graphs of their own. + static func ecgObservation(input: HealthKitECGObservationInput) throws -> Observation { let source = input.source guard source.endDate >= source.startDate else { throw HealthKitConversionError.ecgEvidence(.invalidSourcePeriod) @@ -189,12 +67,7 @@ extension HealthKitConverter { waveform: input.waveform, timeZone: source.timeZone ) - var observation = try baseECGObservation( - source: source, - waveform: input.waveform, - effectivePeriod: period, - subject: graphContext.subject - ) + var observation = baseECGObservation(source: source, waveform: input.waveform, effectivePeriod: period) observation.extension = (observation.extension ?? []) + (try requiredECGExtensions(source: source)) observation.interpretation = [ CodeableConcept(coding: [ @@ -220,53 +93,33 @@ extension HealthKitConverter { ) } } - applyGraphContext( - to: &observation, - graphContext: graphContext, - wasUserEntered: source.wasUserEntered - ) return observation } /// The source's period average is a distinct clinical result derived from the ECG waveform. /// It therefore receives its own output identity and provenance target instead of being hidden /// in a waveform-specific extension or making the waveform claim the reverse relationship. - static func ecgAverageHeartRateChild( - input: HealthKitECGObservationInput, - envelope: GraphEnvelope - ) throws -> GraphChildOutput? { + static func ecgAverageHeartRateChild(input: HealthKitECGObservationInput) throws -> ExchangeOutputDraft? { guard let averageHeartRate = input.source.averageHeartRate else { return nil } guard averageHeartRate.isFinite else { throw HealthKitConversionError.ecgEvidence(.invalidAverageHeartRate) } - let identity = try envelope.sourceRecord.output(role: "average-heart-rate", discriminator: "single") - let effective = try effectivePeriod( - source: input.source, - waveform: input.waveform, - timeZone: input.source.timeZone - ) - let observation = try averageHeartRateObservation( - value: averageHeartRate, - identity: identity, - effective: effective, - input: input, - envelope: envelope - ) - return GraphChildOutput( - identity: identity, - observation: observation, - primaryRelationship: .none + let effective = try effectivePeriod(source: input.source, waveform: input.waveform, timeZone: input.source.timeZone) + return ExchangeOutputDraft( + role: "average-heart-rate", + resource: .observation(try averageHeartRateObservation(value: averageHeartRate, effective: effective, input: input)), + derivedFromPrimary: true, + wasUserEntered: input.source.wasUserEntered ) } private static func baseECGObservation( source: HealthKitECGSourceEvidence, waveform: HealthKitECGValidatedWaveform, - effectivePeriod: Period, - subject: Reference - ) throws -> Observation { + effectivePeriod: Period + ) -> Observation { var observation = Observation( code: CodeableConcept( coding: [ @@ -277,7 +130,6 @@ extension HealthKitConverter { ) applySourceTypeLineage(source.sourceTypeIdentifier, to: &observation) observation.meta = Meta(profile: HealthKitContract.electrocardiogramProfiles) - observation.subject = subject // `issued` is deliberately absent. It states when this version of the record became // available, and HealthKit keeps no per-object modification time to answer that; a wall // clock would make an unchanged sample convert differently on every run. The conversion @@ -338,31 +190,6 @@ extension HealthKitConverter { ] } - static func applyGraphContext( - to observation: inout Observation, - graphContext: HealthKitGraphContext, - wasUserEntered: Bool - ) { - if wasUserEntered { - applyManualRecordingMethod(to: &observation) - } - if let recordingDeviceURL = graphContext.recordingDeviceURL { - observation.device = Reference(reference: recordingDeviceURL.asFHIRStringPrimitive()) - } - if let gatewayURL = graphContext.gatewayURL { - observation.append( - extension: Extension( - url: Canonicals.gatewayDevice, - value: .reference(Reference(reference: gatewayURL.asFHIRStringPrimitive())) - ), - behaviour: .replace - ) - } - for study in graphContext.studyReferences { - observation.append(extension: Extension(url: Canonicals.researchStudy, value: .reference(study))) - } - } - private static func effectivePeriod( source: HealthKitECGSourceEvidence, waveform: HealthKitECGValidatedWaveform, diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+GraphAssembly.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+GraphAssembly.swift deleted file mode 100644 index 03491d9e5..000000000 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+GraphAssembly.swift +++ /dev/null @@ -1,447 +0,0 @@ -// -// This source file is part of the Grove open-source project -// -// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) -// -// SPDX-License-Identifier: MIT -// - -#if canImport(HealthKit) - -import FHIRModelsExtensions -import Foundation -import GroveFHIRContract -import HealthKit -import ModelsR4 - - -@available(iOS 18, macOS 15, watchOS 11, *) -extension HealthKitConverter { - struct WriterDevices { - let application: IdentifiedDevice - let host: IdentifiedDevice? - - /// The writer snapshots the graph carries as entries of their own. A snapshot the converter already - /// states is that entry, and the host of a writer that is the converter's application has nothing to connect to. - func entries(excluding stated: Set) -> [IdentifiedDevice] { - guard !stated.contains(application.identity) else { - return [] - } - return [host].compactMap(\.self).filter { !stated.contains($0.identity) } + [application] - } - } - - private struct AssembledGraphResources { - let observation: Observation - let provenance: Provenance - let children: [GraphChildOutput] - } - - /// The identity, device, study and provenance surroundings every emitted graph shares. - /// - /// Resolved from the source sample before the record's own resource exists, so an Observation - /// graph and a recording-document graph agree on identity by construction rather than through - /// two implementations that have to be kept in step. - struct GraphEnvelope { - let source: HealthKitSourceRecord - let sourceRecord: SourceRecordIdentity - let primary: RoledIdentifier - let provenanceNode: EntryNodeKey - let converterApplication: IdentifiedDevice - let converterHost: IdentifiedDevice - let gatewayApplication: IdentifiedDevice? - let recordingDevice: IdentifiedDevice? - let writer: WriterDevices? - let writerEntries: [IdentifiedDevice] - let studyContext: StudyContext - let primaryURL: String - let converterURL: String - let gatewayURL: String? - let recordingDeviceURL: String? - let writerURL: String? - let warnings: [HealthKitConversionWarning] - - var graphContext: HealthKitGraphContext { - HealthKitGraphContext( - subject: studyContext.subjectReference, - recordingDeviceURL: recordingDeviceURL, - gatewayURL: gatewayURL, - studyReferences: studyContext.studyReferences - ) - } - } - - /// One secondary source output and the relationship, if any, the primary output publishes. - struct GraphChildOutput { - enum PrimaryRelationship: Equatable { - case hasMember - case none - } - - let identity: RoledIdentifier - let observation: Observation - let primaryRelationship: PrimaryRelationship - } - - private struct SourceIdentities { - let sourceRecord: SourceRecordIdentity - let primary: RoledIdentifier - let provenanceNode: EntryNodeKey - } - - private struct ConverterSnapshots { - let host: IdentifiedDevice - let application: IdentifiedDevice - let applicationURL: String - /// A distinct application that mediated the measurement; the converter itself when it did. - let gateway: IdentifiedDevice? - let gatewayURL: String? - - var identities: Set { - Set([host, application, gateway].compactMap { $0?.identity }) - } - } - - /// Resolves all graph identities and device snapshots as one transaction. - static func graphEnvelope( - for sample: HKSample, - context: HealthKitConversionContext, - outputRole: String, - outputDiscriminator: String = "single" - ) throws -> GraphEnvelope { - guard let type = HealthKitSourceType(sample) else { - throw HealthKitConversionError.unregisteredSourceType(sample.sampleType.identifier) - } - let sourceUUID = sample.uuid.uuidString.lowercased() - let identities = try sourceIdentities( - type: type, - sourceUUID: sourceUUID, - outputRole: outputRole, - outputDiscriminator: outputDiscriminator, - context: context - ) - let converter = try converterSnapshots(context: context) - var recordingDevice = try Self.recordingDevice(for: sample.device, context: context) - if context.options.writer == .device, recordingDevice.device == nil { - recordingDevice = try Self.recordingDevice(fromSource: sample.sourceRevision, context: context) - } - let writer = try Self.writer( - for: sample.sourceRevision, - classification: context.options.writer, - context: context - ) - let writerEntries = writer?.entries(excluding: converter.identities) ?? [] - try validateRepositoryIDs(recordingDevice: recordingDevice.device, writer: writer, writerEntries: writerEntries, context: context) - let recordingDeviceURL = try recordingDevice.device.map { try $0.identity.fullURLString } - let writerURL = try resolvedWriterURL( - writer, - classification: context.options.writer, - recordingDeviceURL: recordingDeviceURL - ) - return GraphEnvelope( - source: HealthKitSourceRecord(uuid: sample.uuid, type: type), - sourceRecord: identities.sourceRecord, - primary: identities.primary, - provenanceNode: identities.provenanceNode, - converterApplication: converter.application, - converterHost: converter.host, - gatewayApplication: converter.gateway, - recordingDevice: recordingDevice.device, - writer: writer, - writerEntries: writerEntries, - studyContext: try context.event.studyContext(), - primaryURL: try identities.primary.fullURLString, - converterURL: converter.applicationURL, - gatewayURL: converter.gatewayURL, - recordingDeviceURL: recordingDeviceURL, - writerURL: writerURL, - warnings: warnings(for: sample, recordingDevice: recordingDevice) - ) - } - - private static func sourceIdentities( - type: HealthKitSourceType, - sourceUUID: String, - outputRole: String, - outputDiscriminator: String, - context: HealthKitConversionContext - ) throws -> SourceIdentities { - let sourceRecord = try context.identityScope.sourceRecord( - adapterID: HealthKitConverter.adapterID, - sourceType: type.rawValue, - repositoryScope: context.repositoryScope, - nativeRecordID: sourceUUID - ) - return SourceIdentities( - sourceRecord: sourceRecord, - primary: try sourceRecord.output(role: outputRole, discriminator: outputDiscriminator), - provenanceNode: try EntryNodeKey( - system: context.entryNodeIdentifierSystem, - event: context.eventIdentifier, - nodeRole: "conversion-provenance", - ordinal: 0 - ) - ) - } - - private static func converterSnapshots(context: HealthKitConversionContext) throws -> ConverterSnapshots { - let host = try hostSnapshot(context.event.host, repositoryID: context.repositoryID(.hostDevice), context: context) - let application = try applicationSnapshot( - context.event.application, - parentURL: try host.identity.fullURLString, - repositoryID: context.repositoryID(.applicationDevice), - context: context - ) - let applicationURL = try application.identity.fullURLString - switch context.event.converterRole { - case .assembler: - return ConverterSnapshots(host: host, application: application, applicationURL: applicationURL, gateway: nil, gatewayURL: nil) - case .gateway: - return ConverterSnapshots( - host: host, application: application, applicationURL: applicationURL, gateway: nil, gatewayURL: applicationURL - ) - case .gatewayApplication(let gatewayApplication): - let gateway = try applicationSnapshot(gatewayApplication, parentURL: nil, repositoryID: nil, context: context) - return ConverterSnapshots( - host: host, - application: application, - applicationURL: applicationURL, - gateway: gateway, - gatewayURL: try gateway.identity.fullURLString - ) - } - } - - /// What any graph of the sample does not carry although the sample did. - private static func warnings( - for sample: HKSample, - recordingDevice: ResolvedRecordingDevice - ) -> [HealthKitConversionWarning] { - var warnings: [HealthKitConversionWarning] = [] - if let warning = recordingDevice.warning { - warnings.append(warning) - } - let unmodeled = (sample.metadata ?? [:]).keys.filter { !HealthKitMetadataField.keys.contains($0) }.sorted() - if !unmodeled.isEmpty { - warnings.append(.unmodeledMetadataWithheld(keys: unmodeled)) - } - return warnings - } - - /// The effective elements the outputs serialized in UTC because the sample named no time zone, each once. - private static func sourceOffsetWarnings( - for sample: HKSample, - outputs: [Observation] - ) -> [HealthKitConversionWarning] { - guard sample.metadata?[HKMetadataKeyTimeZone] == nil else { - return [] - } - var fields: [String] = [] - for output in outputs { - let elements = switch output.effective { - case .dateTime: ["Observation.effectiveDateTime"] - case .period: ["Observation.effectivePeriod.start", "Observation.effectivePeriod.end"] - case .instant, .timing, nil: [String]() - } - fields += elements.filter { !fields.contains($0) } - } - return fields.map { .sourceOffsetUnavailable(field: $0) } - } - - private static func validateRepositoryIDs( - recordingDevice: IdentifiedDevice?, - writer: WriterDevices?, - writerEntries: [IdentifiedDevice], - context: HealthKitConversionContext - ) throws(HealthKitConversionError) { - let entries = Set(writerEntries.map(\.identity)) - if context.repositoryID(.recordingDevice) != nil, recordingDevice == nil { - throw .repositoryIDWithoutNode(.recordingDevice) - } - if context.repositoryID(.writer) != nil, !entries.contains(where: { $0 == writer?.application.identity }) { - throw .repositoryIDWithoutNode(.writer) - } - if context.repositoryID(.writerHost) != nil, !entries.contains(where: { $0 == writer?.host?.identity }) { - throw .repositoryIDWithoutNode(.writerHost) - } - } - - private static func resolvedWriterURL( - _ writer: WriterDevices?, - classification: HealthKitWriter, - recordingDeviceURL: String? - ) throws -> String? { - if let writer { - return try writer.application.identity.fullURLString - } - return classification == .device ? recordingDeviceURL : nil - } - - /// Builds the self-contained exchange Bundle for one source record. - static func exchangeBundle( - envelope: GraphEnvelope, - primary: ResourceProxy, - members: [(identity: RoledIdentifier, resource: ResourceProxy)] = [], - provenance: Provenance, - context: HealthKitConversionContext - ) throws -> ExchangeGraph { - var entries = [try BundleEntry(identifier: envelope.primary, resource: primary)] - for member in members { - entries.append(try BundleEntry(identifier: member.identity, resource: member.resource)) - } - entries.append(contentsOf: envelope.studyContext.allEntries) - entries.append(contentsOf: try deviceEntries(envelope: envelope)) - entries.append(try BundleEntry( - identifier: envelope.provenanceNode.identifier, - resource: ResourceProxy(with: provenance) - )) - - var bundle = Bundle( - entry: entries, - identifier: context.eventIdentifier.identifier.fhirIdentifier, - meta: Meta(profile: [Profile.groveMobileExchangeBundle]), - timestamp: FHIRPrimitive(try Instant(utc: context.conversionInstant)), - type: FHIRPrimitive(.collection) - ) - bundle.id = context.repositoryID(.bundle)?.primitive - return try ExchangeGraph( - kind: .active, - eventIdentifier: context.eventIdentifier, - bundle: bundle - ) - } - - /// Every Device snapshot of the graph, in its fixed entry order. - private static func deviceEntries(envelope: GraphEnvelope) throws -> [BundleEntry] { - var devices: [IdentifiedDevice] = [] - if let recordingDevice = envelope.recordingDevice { - devices.append(recordingDevice) - } - devices.append(envelope.converterHost) - devices.append(envelope.converterApplication) - if let gateway = envelope.gatewayApplication { - devices.append(gateway) - } - devices.append(contentsOf: envelope.writerEntries) - return try devices.map { try BundleEntry(identifier: $0.identity, resource: ResourceProxy(with: $0.resource)) } - } - - static func identifiers( - envelope: GraphEnvelope, - context: HealthKitConversionContext, - childOutputs: [RoledIdentifier] = [], - sourceArtifact: RoledIdentifier? = nil - ) -> ExchangeGraphIdentifiers { - ExchangeGraphIdentifiers( - event: context.eventIdentifier.identifier, - sourceRecord: envelope.sourceRecord.identifier, - primaryOutput: envelope.primary, - applicationSnapshot: envelope.converterApplication.identity, - hostSnapshot: envelope.converterHost.identity, - provenance: envelope.provenanceNode.identifier, - childOutputs: childOutputs, - sourceArtifact: sourceArtifact, - recordingDeviceSnapshot: envelope.recordingDevice?.identity, - writerSnapshot: envelope.writer?.application.identity, - writerHostSnapshot: envelope.writerEntries.isEmpty ? nil : envelope.writer?.host?.identity - ) - } - - static func assembleGraph( - for sample: HKSample, - context: HealthKitConversionContext, - outputRole: String, - outputDiscriminator: String = "single", - childBuilder: ((_ envelope: GraphEnvelope) throws -> [GraphChildOutput])? = nil, - observationBuilder: (_ graphContext: HealthKitGraphContext) throws -> Observation - ) throws -> HealthKitConversionSet { - let envelope = try graphEnvelope( - for: sample, - context: context, - outputRole: outputRole, - outputDiscriminator: outputDiscriminator - ) - let resources = try assembledGraphResources( - sample: sample, - envelope: envelope, - context: context, - childBuilder: childBuilder, - observationBuilder: observationBuilder - ) - let graph = try exchangeBundle( - envelope: envelope, - primary: ResourceProxy(with: resources.observation), - members: resources.children.map { ($0.identity, ResourceProxy(with: $0.observation)) }, - provenance: resources.provenance, - context: context - ) - return HealthKitConversionSet( - primary: HealthKitConversion( - source: envelope.source, - identifiers: identifiers(envelope: envelope, context: context, childOutputs: resources.children.map(\.identity)), - graph: graph, - warnings: envelope.warnings + sourceOffsetWarnings( - for: sample, - outputs: [resources.observation] + resources.children.map(\.observation) - ) - ) - ) - } - - private static func assembledGraphResources( - sample: HKSample, - envelope: GraphEnvelope, - context: HealthKitConversionContext, - childBuilder: ((_ envelope: GraphEnvelope) throws -> [GraphChildOutput])?, - observationBuilder: (_ graphContext: HealthKitGraphContext) throws -> Observation - ) throws -> AssembledGraphResources { - var observation = try observationBuilder(envelope.graphContext) - observation.id = context.repositoryID(.primaryOutput)?.primitive - observation.identifier = [ - envelope.sourceRecord.identifier.fhirIdentifier, - envelope.primary.fhirIdentifier - ] + nativeIdentifiers(for: sample, policy: context.options.nativeIdentifierDisclosure) - try applySyncIdentity(of: sample, to: &observation, context: context) - - var provenance = try Self.provenance( - sourceIdentifier: envelope.sourceRecord.identifier.fhirIdentifier, - targetURL: envelope.primaryURL, - converterURL: envelope.converterURL, - writerURL: envelope.writerURL, - recordedAt: context.conversionInstant - ) - provenance.id = context.repositoryID(.provenance)?.primitive - let children = try childBuilder?(envelope) ?? [] - try applyChildRelationships( - children, - primaryURL: envelope.primaryURL, - observation: &observation, - provenance: &provenance - ) - return AssembledGraphResources( - observation: observation, - provenance: provenance, - children: children - ) - } - - private static func applyChildRelationships( - _ children: [GraphChildOutput], - primaryURL: String, - observation: inout Observation, - provenance: inout Provenance - ) throws { - let members = children.filter { $0.primaryRelationship == .hasMember } - if !members.isEmpty { - observation.hasMember = try members.map { member in - Reference(reference: try member.identity.fullURLString.asFHIRStringPrimitive()) - } - } - provenance.target = [Reference(reference: primaryURL.asFHIRStringPrimitive())] - + (try children.map { child in - Reference(reference: try child.identity.fullURLString.asFHIRStringPrimitive()) - }) - } -} - -#endif diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+IdentityMetadata.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+IdentityMetadata.swift deleted file mode 100644 index 8e12be50d..000000000 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+IdentityMetadata.swift +++ /dev/null @@ -1,106 +0,0 @@ -// -// This source file is part of the Grove open-source project -// -// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) -// -// SPDX-License-Identifier: MIT -// - -#if canImport(HealthKit) - -import CoreFoundation -import FHIRModelsExtensions -import Foundation -import GroveFHIRContract -import HealthKit -import ModelsR4 - - -@available(iOS 18, macOS 15, watchOS 11, *) -extension HealthKitConverter { - static func applySyncIdentity( - of sample: HKSample, - to observation: inout Observation, - context: HealthKitConversionContext - ) throws { - try applySyncIdentity( - metadata: sample.metadata, - writerApplication: sample.sourceRevision.source.bundleIdentifier, - to: &observation, - context: context - ) - } - - // HealthKit itself models the metadata dictionary as absent when an object has no metadata. - /// Applies Apple's paired sync metadata after validating it independently of source - /// attribution. Exposed internally so tests can supply the attributable writer that - /// HealthKit's public sample factories do not let a test construct. - static func applySyncIdentity( - metadata: [String: Any]?, // swiftlint:disable:this discouraged_optional_collection - writerApplication: String, - to observation: inout Observation, - context: HealthKitConversionContext - ) throws { - let identifierValue = metadata?[HKMetadataKeySyncIdentifier] - let versionValue = metadata?[HKMetadataKeySyncVersion] - guard identifierValue != nil || versionValue != nil else { - return - } - guard let syncIdentifier = identifierValue as? String, !syncIdentifier.isEmpty else { - throw HealthKitValueFailure.invalidMetadataValue(.syncIdentifier) - } - guard let versionValue else { - throw HealthKitValueFailure.invalidMetadataValue(.syncVersion) - } - let version = try canonicalSyncVersion(versionValue) - - // The writer is part of the writer-record namespace. A valid pair without an attributable - // writer remains omitted rather than being assigned to an invented global/empty writer. - guard !writerApplication.isEmpty else { - return - } - let identity = try context.identityScope.writerRecord( - writerApplication: BusinessIdentifier( - system: IdentifierSystem(Canonicals.appleBundleIdentifierSystem), - value: writerApplication - ), - writerRecordID: syncIdentifier - ) - observation.identifier = (observation.identifier ?? []) + [identity.fhirIdentifier] - observation.extension = (observation.extension ?? []) + [ - Extension( - url: Canonicals.writerRecordVersion, - value: .string(version.asFHIRStringPrimitive()) - ) - ] - } - - private static func canonicalSyncVersion(_ value: Any) throws -> String { - guard let number = value as? NSNumber, - CFGetTypeID(number) != CFBooleanGetTypeID(), - var decimal = Decimal( - string: number.stringValue, - locale: Locale(identifier: "en_US_POSIX") - ), - !decimal.isNaN, - decimal >= 0 else { - throw HealthKitValueFailure.invalidMetadataValue(.syncVersion) - } - var integral = Decimal() - NSDecimalRound(&integral, &decimal, 0, .down) - guard integral == decimal else { - throw HealthKitValueFailure.invalidMetadataValue(.syncVersion) - } - return NSDecimalString(&integral, Locale(identifier: "en_US_POSIX")) - } - - /// Returns the optional caller-governed source-store identifier for the primary output. - static func nativeIdentifiers( - for sample: HKSample, - policy: GovernedSourceIdentifierDisclosurePolicy - ) -> [Identifier] { - [policy.identifier(for: sample.uuid.uuidString.lowercased())].compactMap { $0 } - } -} - -#endif diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+Observation.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+Observation.swift index fcc4a2dac..b5efd5232 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+Observation.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter+Observation.swift @@ -41,10 +41,10 @@ extension HealthKitConverter { MeasurementCatalog.mindfulnessSession.id ] + /// The Observation content of one catalog-bound sample; the envelope adds identities and links. static func observation( for sample: HKSample, - binding: HealthKitFHIRBinding, - graphContext: HealthKitGraphContext + binding: HealthKitFHIRBinding ) throws -> Observation { let contract = binding.contract let primaryCoding = Coding( @@ -65,7 +65,6 @@ extension HealthKitConverter { ) applySourceTypeLineage(sample.sampleType.identifier, to: &observation) observation.meta = Meta(profile: contract.profiles) - observation.subject = graphContext.subject // HealthKit has no per-object availability time. Conversion time belongs on Provenance. observation.category = category(for: contract.id).map { [CodeableConcept(coding: [$0])] } observation.method = contract.method.map { method in @@ -82,11 +81,6 @@ extension HealthKitConverter { try applyHeartRateMotionContext(to: &observation, sample: sample) try applyInsulinDeliveryReason(to: &observation, sample: sample) try applyMenstrualCycleStart(to: &observation, sample: sample, contract: contract) - applyGraphContext( - to: &observation, - graphContext: graphContext, - wasUserEntered: (sample.metadata?[HKMetadataKeyWasUserEntered] as? Bool) == true - ) return observation } diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+RecordingDocuments.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+RecordingDocuments.swift index d7ee2cfb4..5ee3a082e 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+RecordingDocuments.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter+RecordingDocuments.swift @@ -92,31 +92,13 @@ extension HealthKitConverter { context: HealthKitConversionContext ) throws(HealthKitConversionError) -> HealthKitConversionSet { do { - return try Self.convertHeartbeatSeries(record, context: context) + try Self.validate(context: context) + return try HealthKitAssembly(context: context.event).convertHeartbeatSeries(record, request: .init(context: context)) } catch { throw HealthKitConversionError(conversionFailure: error, source: .heartbeatSeries) } } - static func convertHeartbeatSeries( - _ record: HealthKitHeartbeatSeriesRecord, - context: HealthKitConversionContext - ) throws -> HealthKitConversionSet { - try assembleDocumentGraph( - for: record.series, - evidence: HealthKitRecordingEvidence( - outputRole: "native-recording", - format: .beatIntervalSeries, - title: "Heartbeat series beat intervals", - payload: try beatIntervalPayload( - seriesStart: record.series.startDate, - heartbeats: record.heartbeats - ) - ), - context: context - ) - } - /// Converts a workout route into the recording document that carries its track. /// /// - Returns: The route's graph, or `nil` under `RouteDisclosurePolicy.omit`, the default. @@ -128,31 +110,13 @@ extension HealthKitConverter { context: HealthKitConversionContext ) throws(HealthKitConversionError) -> HealthKitConversionSet? { do { - return try Self.convertWorkoutRoute(record, context: context) + try Self.validate(context: context) + return try HealthKitAssembly(context: context.event).convertWorkoutRoute(record, request: .init(context: context)) } catch { throw HealthKitConversionError(conversionFailure: error, source: .workoutRoute) } } - static func convertWorkoutRoute( - _ record: HealthKitWorkoutRouteRecord, - context: HealthKitConversionContext - ) throws -> HealthKitConversionSet? { - guard let payload = try locationTrackPayload(record.locations, context: context) else { - return nil - } - return try assembleDocumentGraph( - for: record.route, - evidence: HealthKitRecordingEvidence( - outputRole: "native-recording", - format: .locationTrackSamples, - title: "Workout route locations", - payload: payload - ), - context: context - ) - } - static func beatIntervalPayload( seriesStart: Date, heartbeats: [HealthKitHeartbeat] @@ -173,14 +137,8 @@ extension HealthKitConverter { return writer.data() } - /// The route's track, or `nil` when the deployment has not authorized disclosing one. - static func locationTrackPayload( - _ locations: [CLLocation], - context: HealthKitConversionContext - ) throws -> Data? { - guard context.options.routeDisclosure == .authorized else { - return nil - } + /// The route's track in the registry's `location-track-samples` column schema. + static func locationTrackPayload(_ locations: [CLLocation]) throws -> Data { guard !locations.isEmpty else { throw HealthKitValueFailure.emptyRecordingSeries } @@ -202,61 +160,9 @@ extension HealthKitConverter { return writer.data() } - static func assembleDocumentGraph( - for sample: HKSample, - evidence: HealthKitRecordingEvidence, - context: HealthKitConversionContext - ) throws -> HealthKitConversionSet { - try validate(context: context) - let envelope = try graphEnvelope( - for: sample, - context: context, - outputRole: evidence.outputRole, - outputDiscriminator: "single" - ) - let artifactIdentity = try envelope.sourceRecord.artifact(formatCode: evidence.format.rawValue, partIndex: 0) - let document = try recordingDocument( - for: sample, - evidence: evidence, - envelope: envelope, - context: context, - artifactIdentity: artifactIdentity - ) - var provenance = try Self.provenance( - sourceIdentifier: envelope.sourceRecord.identifier.fhirIdentifier, - targetURL: envelope.primaryURL, - converterURL: envelope.converterURL, - writerURL: envelope.writerURL, - recordedAt: context.conversionInstant - ) - provenance.id = context.repositoryID(.provenance)?.primitive - - let graph = try exchangeBundle( - envelope: envelope, - primary: ResourceProxy(with: document), - provenance: provenance, - context: context - ) - return HealthKitConversionSet( - primary: HealthKitConversion( - source: envelope.source, - identifiers: identifiers(envelope: envelope, context: context, sourceArtifact: artifactIdentity), - graph: graph, - warnings: envelope.warnings - ) - ) - } - - private static func recordingDocument( - for sample: HKSample, - evidence: HealthKitRecordingEvidence, - envelope: GraphEnvelope, - context: HealthKitConversionContext, - artifactIdentity: RoledIdentifier - ) throws -> DocumentReference { - let sourceTypeIdentifier = sample.sampleType.identifier - var authors = envelope.recordingDeviceURL.map { [Reference(reference: $0.asFHIRStringPrimitive())] } ?? [] - authors.append(Reference(reference: envelope.converterURL.asFHIRStringPrimitive())) + /// The DocumentReference content of one recording document; the envelope adds identities, + /// subject, authors, date and study context. + static func recordingDocument(evidence: HealthKitRecordingEvidence, sourceTypeIdentifier: String) throws -> DocumentReference { let typeCoding = if let clinicalRecordTypeCode = evidence.clinicalRecordTypeCode { Coding( code: clinicalRecordTypeCode.asFHIRStringPrimitive(), @@ -269,7 +175,6 @@ extension HealthKitConverter { ) } var document = DocumentReference( - author: authors, content: [DocumentReferenceContent( attachment: try attachment(evidence), format: Coding( @@ -277,22 +182,11 @@ extension HealthKitConverter { system: HealthKitRecordingDocumentContract.formatCodeSystem ) )], - context: envelope.studyContext.studyReferences.isEmpty - ? nil - : DocumentReferenceContext(related: envelope.studyContext.studyReferences), - date: FHIRPrimitive(try Instant(utc: context.conversionInstant)), - identifier: [ - envelope.sourceRecord.identifier.fhirIdentifier, - envelope.primary.fhirIdentifier, - artifactIdentity.fhirIdentifier - ] + nativeIdentifiers(for: sample, policy: context.options.nativeIdentifierDisclosure), meta: Meta(profile: evidence.profiles), status: FHIRPrimitive(.current), - subject: envelope.graphContext.subject, type: CodeableConcept(coding: [typeCoding]) ) applySourceTypeLineage(sourceTypeIdentifier, to: &document) - document.id = context.repositoryID(.primaryOutput)?.primitive return document } diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+Retraction.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+Retraction.swift index 4813fcf24..88ff19b1a 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+Retraction.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter+Retraction.swift @@ -13,96 +13,6 @@ public import GroveFHIRContract public import HealthKit -@available(iOS 18, macOS 15, watchOS 11, *) -extension HealthKitConverter { - private static func nativeRecordID(of record: HealthKitSourceRecord) -> String { - record.uuid.uuidString.lowercased() - } - - private static func sourceRecord( - for record: HealthKitSourceRecord, - context: HealthKitConversionContext - ) throws(HealthKitConversionError) -> SourceRecordIdentity { - do { - return try context.identityScope.sourceRecord( - adapterID: adapterID, - sourceType: record.type.rawValue, - repositoryScope: context.repositoryScope, - nativeRecordID: nativeRecordID(of: record) - ) - } catch { - throw .opaqueIdentity(error) - } - } - - /// The complete retraction of a deleted record, as its own exchange event. - /// - /// `context` is a fresh context for the retraction's event, under the same identity scope, - /// repository scope and native-identifier disclosure as the record's conversion. The source - /// record and every target are recomputed from `record`, so nothing from that conversion needs - /// to be kept. - static func retraction( - for record: HealthKitSourceRecord, - context: HealthKitConversionContext, - occurred: RetractionOccurrence - ) throws(HealthKitConversionError) -> RetractionEvent { - let targets = try retractionTargets(for: record, context: context) - let sourceRecord = try Self.sourceRecord(for: record, context: context) - do throws(RetractionEventError) { - return try RetractionEvent( - targets: targets, - context: context.event, - sourceRecord: sourceRecord.identifier, - occurred: occurred - ) - } catch { - throw HealthKitConversionError(error) - } - } - - /// The logical targets a deletion retracts, named from the catalog alone. - /// - /// A deleted sample is gone, so the outputs its addition minted are recomputed from the source - /// type: the same identity scope and the same output roles yield the same identifiers. The - /// sample's UUID rides along as each target's native record identifier exactly when the - /// context's native-identifier disclosure authorizes it on the addition path. - static func retractionTargets( - for record: HealthKitSourceRecord, - context: HealthKitConversionContext - ) throws(HealthKitConversionError) -> [RetractionTarget] { - try validate(context: context) - let outputs = HealthKitCatalog.outputs(for: record.type) - guard !outputs.isEmpty else { - throw Self.unconvertibleSampleError(for: record.type) - } - let nativeRecordIdentifier = context.options.nativeIdentifierDisclosure.nativeRecordIdentifier( - for: nativeRecordID(of: record) - ) - let sourceRecord = try Self.sourceRecord(for: record, context: context) - var targets: [RetractionTarget] = [] - for output in outputs { - let identity: RoledIdentifier - do { - identity = try sourceRecord.output(role: output.role, discriminator: output.discriminator) - } catch { - throw .opaqueIdentity(error) - } - do { - targets.append(try RetractionTarget( - identifier: identity, - resourceType: output.resourceType, - role: output.retractionRole, - nativeRecordIdentifier: nativeRecordIdentifier - )) - } catch { - throw .dependency(HealthKitDependencyFailure(underlying: error)) - } - } - return targets - } -} - - @available(iOS 18, macOS 15, watchOS 11, *) extension HealthKitConverter { /// The complete retraction of a deleted record, as its own exchange event. @@ -112,7 +22,8 @@ extension HealthKitConverter { context: HealthKitConversionContext, occurred: RetractionOccurrence ) throws(HealthKitConversionError) -> RetractionEvent { - try Self.retraction(for: record, context: context, occurred: occurred) + try Self.validate(context: context) + return try HealthKitAssembly(context: context.event).retraction(of: record, request: .init(context: context), occurred: occurred) } /// The logical targets a deletion retracts, named from the catalog alone. @@ -121,7 +32,8 @@ extension HealthKitConverter { for record: HealthKitSourceRecord, context: HealthKitConversionContext ) throws(HealthKitConversionError) -> [RetractionTarget] { - try Self.retractionTargets(for: record, context: context) + try Self.validate(context: context) + return try HealthKitAssembly(context: context.event).retractionTargets(of: record, request: .init(context: context)) } } diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+WorkoutSegments.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+WorkoutSegments.swift index c7c147cd9..ee9b39e4f 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+WorkoutSegments.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter+WorkoutSegments.swift @@ -6,10 +6,8 @@ // SPDX-License-Identifier: MIT // -// Segment construction stays contiguous so interval, identity, and reference ordering are auditable. -// swiftlint:disable function_body_length function_parameter_count - #if canImport(HealthKit) + import Foundation import GroveFHIRContract import HealthKit @@ -24,13 +22,9 @@ extension HealthKitConverter { /// per-activity intervals that describe a multi-sport session. Converting only the totals turns a /// triathlon into a single Observation, so each is emitted as its own segment linked from the /// session through `hasMember`. - static func workoutSegments( - _ workout: HKWorkout, - envelope: GraphEnvelope - ) throws -> [(identity: RoledIdentifier, observation: Observation)] { - let sourceRecord = envelope.sourceRecord.identifier + static func workoutSegments(_ workout: HKWorkout) throws -> [ExchangeOutputDraft] { let sourceTimeZone = try sourceTimeZone(metadata: workout.metadata ?? [:]) - var segments: [(identity: RoledIdentifier, observation: Observation)] = [] + var segments: [ExchangeOutputDraft] = [] var eventOccurrences: [String: Int] = [:] for event in workout.workoutEvents ?? [] { let coordinate = try segmentCoordinate( @@ -39,10 +33,9 @@ extension HealthKitConverter { ) let occurrence = eventOccurrences[coordinate, default: 0] eventOccurrences[coordinate] = occurrence + 1 - let identity = try envelope.sourceRecord.output(role: "workout-segment", discriminator: "\(coordinate):\(occurrence)") - segments.append(( - identity: identity, - observation: try segmentObservation( + segments.append(segment( + discriminator: "\(coordinate):\(occurrence)", + observation: segmentObservation( value: segmentValue(for: event.type), effective: try effectivePeriod( start: event.dateInterval.start, @@ -50,10 +43,7 @@ extension HealthKitConverter { sourceTimeZone: sourceTimeZone ), components: [], - sourceTypeIdentifier: workout.sampleType.identifier, - subject: envelope.graphContext.subject, - sourceRecord: sourceRecord, - output: identity + sourceTypeIdentifier: workout.sampleType.identifier ) )) } @@ -70,17 +60,13 @@ extension HealthKitConverter { ) let occurrence = activityOccurrences[coordinate, default: 0] activityOccurrences[coordinate] = occurrence + 1 - let identity = try envelope.sourceRecord.output(role: "workout-segment", discriminator: "\(coordinate):\(occurrence)") - segments.append(( - identity: identity, - observation: try segmentObservation( + segments.append(segment( + discriminator: "\(coordinate):\(occurrence)", + observation: segmentObservation( value: try workoutValue(activityType: activity.workoutConfiguration.activityType), effective: try effectivePeriod(start: activity.startDate, end: end, sourceTimeZone: sourceTimeZone), components: try activityComponents(activity), - sourceTypeIdentifier: workout.sampleType.identifier, - subject: envelope.graphContext.subject, - sourceRecord: sourceRecord, - output: identity + sourceTypeIdentifier: workout.sampleType.identifier ) )) } @@ -99,15 +85,23 @@ extension HealthKitConverter { return "\(kind):\(String(groveFHIRPlainDecimal: start)):\(String(groveFHIRPlainDecimal: end))" } + /// A segment hangs off the session as a `hasMember` child and states only its subject. + private static func segment(discriminator: String, observation: Observation) -> ExchangeOutputDraft { + ExchangeOutputDraft( + role: "workout-segment", + discriminator: discriminator, + resource: .observation(observation), + links: [.subject], + memberOfPrimary: true + ) + } + private static func segmentObservation( value: CodeableConcept, effective: Period, components: [ObservationComponent], - sourceTypeIdentifier: String, - subject: Reference, - sourceRecord: RoledIdentifier, - output: RoledIdentifier - ) throws -> Observation { + sourceTypeIdentifier: String + ) -> Observation { var observation = Observation( code: CodeableConcept(coding: [ Coding( @@ -119,8 +113,6 @@ extension HealthKitConverter { ) applySourceTypeLineage(sourceTypeIdentifier, to: &observation) observation.meta = Meta(profile: [Profile.groveMobileWorkoutSegment]) - observation.identifier = [sourceRecord.fhirIdentifier, output.fhirIdentifier] - observation.subject = subject observation.effective = .period(effective) observation.value = .codeableConcept(value) observation.component = components.isEmpty ? nil : components diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter.swift index 852a5364c..88c0875dc 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter.swift @@ -31,7 +31,8 @@ public struct HealthKitConverter: Sendable { context: HealthKitConversionContext ) throws(HealthKitConversionError) -> HealthKitConversionSet { do { - return try Self.convertSample(sample, context: context) + try Self.validate(context: context) + return try HealthKitAssembly(context: context.event).convert(sample, request: .init(context: context)) } catch { throw HealthKitConversionError(conversionFailure: error, source: HealthKitSourceType(sample)) } @@ -80,53 +81,6 @@ extension HealthKitConverter { /// sample itself, as `com.apple.health.`. static let appleDeviceSourcePrefix = "com.apple.health." - static func convertSample( - _ sample: HKSample, - context: HealthKitConversionContext - ) throws -> HealthKitConversionSet { - try validate(context: context) - guard let type = HealthKitSourceType(sample) else { - throw HealthKitConversionError.unregisteredSourceType(sample.sampleType.identifier) - } - if sample is HKElectrocardiogram { - throw HealthKitConversionError.ecgEvidence(.evidenceRequired) - } - #if !os(watchOS) - if let record = sample as? HKClinicalRecord { - return try convertClinicalRecord(record, context: context) - } - if let document = sample as? HKCDADocumentSample { - return try convertClinicalDocument(document, context: context) - } - #endif - guard let binding = HealthKitCatalog.binding(for: sample), - let output = HealthKitCatalog.primaryOutput(for: type) else { - throw unconvertibleSampleError(for: type) - } - return try assembleGraph( - for: sample, - context: context, - outputRole: output.role, - outputDiscriminator: output.discriminator, - childBuilder: (sample as? HKWorkout).map(workoutChildBuilder(for:)) - ) { graphContext in - try observation(for: sample, binding: binding, graphContext: graphContext) - } - } - - /// A workout's segments hang off its session totals as `hasMember` children. - private static func workoutChildBuilder(for workout: HKWorkout) -> (GraphEnvelope) throws -> [GraphChildOutput] { - { envelope in - try workoutSegments(workout, envelope: envelope).map { segment in - GraphChildOutput( - identity: segment.identity, - observation: segment.observation, - primaryRelationship: .hasMember - ) - } - } - } - /// The catalog-driven reason a sample without a binding fails closed. static func unconvertibleSampleError(for type: HealthKitSourceType) -> HealthKitConversionError { if type == .bloodPressureSystolic || type == .bloodPressureDiastolic { diff --git a/Sources/GroveHealthKitFHIR/HealthKitECGGraphInput.swift b/Sources/GroveHealthKitFHIR/HealthKitECGGraphInput.swift index f9a0de883..2755f923f 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitECGGraphInput.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitECGGraphInput.swift @@ -14,16 +14,6 @@ import HealthKit import ModelsR4 -/// The graph surroundings every output of one event states. -struct HealthKitGraphContext: Sendable { - let subject: Reference - let recordingDeviceURL: String? - /// The application that mediated the measurement, when the converter role names one. - let gatewayURL: String? - let studyReferences: [Reference] -} - - @available(iOS 18, macOS 15, watchOS 11, *) struct HealthKitECGEvidence: Sendable { let source: HealthKitECGSourceEvidence diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift index c0b20ea0f..cf75a598a 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift @@ -48,24 +48,14 @@ extension HealthKitFHIRExporter { reservation: ExchangeEventReservation, producerInstance: UUID ) throws -> ExchangeGraph { - let event = ExchangeEventContext( - subject: producer.subject, + let request = HealthKitAssembly.Request( event: try ExchangeEventIdentifier( system: producer.identityScope.systems.event, producerInstance: producerInstance, sequence: reservation.sequence ), - identityScope: producer.identityScope, - repositoryScope: repositoryScope, - application: producer.application, - host: producer.host, - conversionInstant: reservation.instant, - converterRole: .assembler, - studies: producer.studies, - repositoryIDs: try legacyRepositoryIDs(for: deletion.uuid) - ) - let context = HealthKitConversionContext( - event: event, + instant: reservation.instant, + repositoryIDs: try legacyRepositoryIDs(for: deletion.uuid), options: HealthKitConversionOptions(nativeIdentifierDisclosure: options.nativeIdentifier) ) let record = HealthKitSourceRecord(uuid: deletion.uuid, type: deletion.sourceType) @@ -75,7 +65,7 @@ extension HealthKitFHIRExporter { start: deletion.deletedAfter.flatMap { $0 <= deletion.detectedAt ? $0 : nil }, end: deletion.detectedAt ) - return try HealthKitConverter.retraction(for: record, context: context, occurred: occurred).graph + return try assembly.retraction(of: record, request: request, occurred: occurred).graph } } diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift index 3d3e8aa0d..f26afcdf9 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift @@ -32,6 +32,7 @@ public final class HealthKitFHIRExporter: Sendable { /// The business identifier naming this installation's HealthKit store; it enters every source identity. public let repositoryScope: BusinessIdentifier public let options: Options + let assembly: HealthKitAssembly public init( producer: ExchangeProducer, @@ -45,6 +46,15 @@ public final class HealthKitFHIRExporter: Sendable { self.producer = producer self.repositoryScope = repositoryScope self.options = options + self.assembly = HealthKitAssembly(envelope: ExchangeEnvelope( + adapter: HealthKitAssembly.adapter, + identityScope: producer.identityScope, + subject: producer.subject, + repositoryScope: repositoryScope, + application: producer.application, + host: producer.host, + studies: producer.studies + )) } /// Converts samples in input order, calling `receive` once per produced graph or refusal as soon as @@ -133,26 +143,20 @@ extension HealthKitFHIRExporter { reservations: [ExchangeEventReservation], producerInstance: UUID ) throws -> HealthKitConversionSet? { - let context = try conversionContext(for: record.sample, reservation: reservations[0], producerInstance: producerInstance) + let request = try request(for: record.sample, reservation: reservations[0], producerInstance: producerInstance) switch record { case .sample(let sample): - return try HealthKitConverter.convertSample(sample, context: context) + return try assembly.convert(sample, request: request) case let .electrocardiogram(ecg, voltages, symptoms): - let symptomContexts = try zip(symptoms, reservations.dropFirst()).map { symptom, reservation in - try conversionContext(for: symptom, reservation: reservation, producerInstance: producerInstance) + let symptomRequests = try zip(symptoms, reservations.dropFirst()).map { symptom, reservation in + try self.request(for: symptom, reservation: reservation, producerInstance: producerInstance) } let ecgRecord = HealthKitECGRecord(electrocardiogram: ecg, voltageMeasurements: voltages, correlatedSymptoms: symptoms) - return try HealthKitConverter.convertECG(ecgRecord, context: context, symptomContexts: symptomContexts) + return try assembly.convertECG(ecgRecord, request: request, symptomRequests: symptomRequests) case let .heartbeatSeries(series, beats): - return try HealthKitConverter.convertHeartbeatSeries( - HealthKitHeartbeatSeriesRecord(series: series, heartbeats: beats), - context: context - ) + return try assembly.convertHeartbeatSeries(HealthKitHeartbeatSeriesRecord(series: series, heartbeats: beats), request: request) case let .workoutRoute(route, locations): - return try HealthKitConverter.convertWorkoutRoute( - HealthKitWorkoutRouteRecord(route: route, locations: locations), - context: context - ) + return try assembly.convertWorkoutRoute(HealthKitWorkoutRouteRecord(route: route, locations: locations), request: request) } } @@ -187,37 +191,30 @@ extension HealthKitFHIRExporter.Plan { @available(iOS 18, macOS 15, watchOS 11, *) extension HealthKitFHIRExporter { - /// The per-event conversion inputs, in the shape the conversion pipeline still takes. - func conversionContext( + /// One record's event and the policies the options resolve for its source. + func request( for sample: HKSample, reservation: ExchangeEventReservation, producerInstance: UUID - ) throws -> HealthKitConversionContext { + ) throws -> HealthKitAssembly.Request { let source = sample.sourceRevision.source - let event = ExchangeEventContext( - subject: producer.subject, + return HealthKitAssembly.Request( event: try ExchangeEventIdentifier( system: producer.identityScope.systems.event, producerInstance: producerInstance, sequence: reservation.sequence ), - identityScope: producer.identityScope, - repositoryScope: repositoryScope, - application: producer.application, - host: producer.host, - conversionInstant: reservation.instant, + instant: reservation.instant, converterRole: options.role.converterRole(for: source, application: producer.application), - studies: producer.studies, - repositoryIDs: try legacyRepositoryIDs(for: sample.uuid) - ) - let conversionOptions = HealthKitConversionOptions( - writer: options.writer.classification(of: source), - recordingDevice: options.recordingDevice.resolver, - udiDisclosure: options.udi == .authorized ? .authorizedUDI : .omit, - routeDisclosure: options.route == .authorized ? .authorized : .omit, - nativeIdentifierDisclosure: options.nativeIdentifier + repositoryIDs: try legacyRepositoryIDs(for: sample.uuid), + options: HealthKitConversionOptions( + writer: options.writer.classification(of: source), + recordingDevice: options.recordingDevice.resolver, + udiDisclosure: options.udi == .authorized ? .authorizedUDI : .omit, + routeDisclosure: options.route == .authorized ? .authorized : .omit, + nativeIdentifierDisclosure: options.nativeIdentifier + ) ) - return HealthKitConversionContext(event: event, options: conversionOptions) } func legacyRepositoryIDs(for uuid: UUID) throws -> [ExchangeGraphNode: RepositoryID] { diff --git a/Tests/GroveHealthKitFHIRTests/ConformanceFixtureTests.swift b/Tests/GroveHealthKitFHIRTests/ConformanceFixtureTests.swift index 85b88f635..94d85e14c 100644 --- a/Tests/GroveHealthKitFHIRTests/ConformanceFixtureTests.swift +++ b/Tests/GroveHealthKitFHIRTests/ConformanceFixtureTests.swift @@ -437,22 +437,17 @@ struct ConformanceFixtureTests { 72, effective: .dateTime("2026-08-20T08:20:00-07:00") ) - let ecgConversion = try HealthKitConverter.assembleGraph( + let ecgPrimary = ExchangeOutputDraft( + role: "electrocardiogram", + resource: .observation(try HealthKitConverter.ecgObservation(input: ecgInput)) + ) + let ecgOutputs = [ecgPrimary] + [try HealthKitConverter.ecgAverageHeartRateChild(input: ecgInput)].compactMap(\.self) + let ecgConversion = HealthKitConversionSet(primary: try HealthKitAssembly(context: ecgContext.event).graph( for: ecgEnvelopeSource, - context: ecgContext, - outputRole: "electrocardiogram", - childBuilder: { envelope in - guard let companion = try HealthKitConverter.ecgAverageHeartRateChild( - input: ecgInput, - envelope: envelope - ) else { - return [] - } - return [companion] - } - ) { graphContext in - try HealthKitConverter.ecgObservation(input: ecgInput, graphContext: graphContext) - } + type: .heartRate, + outputs: ecgOutputs, + request: .init(context: ecgContext) + )) let ecgObservation = ecgConversion.observation let ecgStudies = ecgObservation.extension?.filter { $0.url == Canonicals.researchStudy } ?? [] #expect(ecgStudies.map(\.value) == quantityStudies.map(\.value)) diff --git a/Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark.swift b/Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark.swift index ccd4e0b4c..93be58d5a 100644 --- a/Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark.swift +++ b/Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark.swift @@ -179,10 +179,7 @@ struct ConversionThroughputBenchmark { let type = try #require(HealthKitSourceType(sample)) let output = try #require(HealthKitCatalog.primaryOutput(for: type)) let binding = try #require(HealthKitCatalog.binding(for: sample)) - let envelope = try HealthKitConverter.graphEnvelope( - for: sample, context: context, outputRole: output.role, outputDiscriminator: output.discriminator - ) - let observation = try HealthKitConverter.observation(for: sample, binding: binding, graphContext: envelope.graphContext) + let observation = try HealthKitConverter.observation(for: sample, binding: binding) let profiles = ExchangeGraph.canonicalStrings(observation.meta?.profile ?? []) let admitted = Set(ExchangeGraph.canonicalStrings( ProfileClaims.adapterProvenanceTargetProfiles[HealthKitContract.conversionProvenanceProfile.value!.url.absoluteString] ?? [] @@ -190,9 +187,9 @@ struct ConversionThroughputBenchmark { print("BENCH diagnose withEvents=\(withEvents) type=\(type.rawValue) role=\(output.role)/\(output.discriminator) " + "primaryProfiles=\(profiles) admittedCount=\(admitted.count) primaryAdmitted=\(!admitted.isDisjoint(with: profiles))") let workout = try #require(sample as? HKWorkout) - let segments = try HealthKitConverter.workoutSegments(workout, envelope: envelope) - for segment in segments.prefix(1) { - let segmentProfiles = ExchangeGraph.canonicalStrings(segment.observation.meta?.profile ?? []) + let segments = try HealthKitConverter.workoutSegments(workout) + for case .observation(let segment) in segments.prefix(1).map(\.resource) { + let segmentProfiles = ExchangeGraph.canonicalStrings(segment.meta?.profile ?? []) print("BENCH diagnose segments=\(segments.count) segmentProfiles=\(segmentProfiles) " + "segmentAdmitted=\(!admitted.isDisjoint(with: segmentProfiles))") } @@ -394,27 +391,18 @@ struct ConversionThroughputBenchmark { run.report.line("scenario=\(run.name) phase=JSONDecoder-decode-bundle \(run.rate(decodeSeconds))") } - /// Construction pieces: identities + device snapshots + study context, then the clinical content alone. + /// Construction pieces: the source facts (devices, writer, identifiers), then the clinical content alone. private func measureConstruction(_ run: ScenarioRun) throws { - var envelopes: [HealthKitConverter.GraphEnvelope] = [] - envelopes.reserveCapacity(run.count) - let type = HealthKitSourceType(run.samples[0])! - let output = HealthKitCatalog.primaryOutput(for: type)! - let envelopeSeconds = try Stopwatch.seconds { + let factsSeconds = try Stopwatch.seconds { for index in 0..) -> [IdentifiedDevice] { + ExchangeGraphAssembler.writerEntries(application: application, host: host, stated: stated) + } + } + + static func convertSample(_ sample: HKSample, context: HealthKitConversionContext) throws -> HealthKitConversionSet { + try validate(context: context) + return try HealthKitAssembly(context: context.event).convert(sample, request: .init(context: context)) + } + + static func retraction( + for record: HealthKitSourceRecord, + context: HealthKitConversionContext, + occurred: RetractionOccurrence + ) throws -> RetractionEvent { + try HealthKitAssembly(context: context.event).retraction(of: record, request: .init(context: context), occurred: occurred) + } + + /// `ecg` supplies only the envelope's identity, device and source facts; the evidence is given. + static func convertECG( + _ ecg: HKSample, + evidence: HealthKitECGEvidence, + symptoms: [HKCategorySample], + context: HealthKitConversionContext, + symptomContexts: [HealthKitConversionContext] + ) throws -> HealthKitConversionSet { + try HealthKitAssembly(context: context.event).convertECG( + ecg, + evidence: evidence, + symptoms: symptoms, + request: .init(context: context), + symptomRequests: symptomContexts.map { .init(context: $0) } + ) + } + + /// One recording document under `sample`'s envelope, whatever the sample's own type. + static func assembleDocumentGraph( + for sample: HKSample, + evidence: HealthKitRecordingEvidence, + context: HealthKitConversionContext + ) throws -> HealthKitConversionSet { + try validate(context: context) + guard let type = HealthKitSourceType(sample) else { + throw HealthKitConversionError.unregisteredSourceType(sample.sampleType.identifier) + } + return try HealthKitAssembly(context: context.event).documentGraph(for: sample, type: type, evidence: evidence, request: .init(context: context)) + } + + /// The route's track, or `nil` when the context does not authorize disclosing one. + static func locationTrackPayload(_ locations: [CLLocation], context: HealthKitConversionContext) throws -> Data? { + guard context.options.routeDisclosure == .authorized else { + return nil + } + return try locationTrackPayload(locations) + } + + // HealthKit itself models the metadata dictionary as absent when an object has no metadata. + /// Applies Apple's paired sync metadata exactly as the assembler decorates an output with it. + static func applySyncIdentity( + metadata: [String: Any]?, // swiftlint:disable:this discouraged_optional_collection + writerApplication: String, + to observation: inout Observation, + context: HealthKitConversionContext + ) throws { + guard let record = try HealthKitAssembly.SourceFacts.writerRecord(metadata: metadata, writerApplication: writerApplication) else { + return + } + let identity = try context.identityScope.writerRecord( + writerApplication: BusinessIdentifier( + system: IdentifierSystem(Canonicals.appleBundleIdentifierSystem), + value: record.writerApplication + ), + writerRecordID: record.syncIdentifier + ) + observation.identifier = (observation.identifier ?? []) + [identity.fhirIdentifier] + observation.extension = (observation.extension ?? []) + [ + Extension(url: Canonicals.writerRecordVersion, value: .string(record.version.asFHIRStringPrimitive())) + ] + } +} + +#endif From 2569b5c4cab484aab3ee21a0a91cae779b33212b Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sat, 3 Oct 2026 16:21:13 +0200 Subject: [PATCH 007/220] Apply the Guide's Envelope Rules and Export Workouts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes from the verified step-6 specifications that live in the envelope, the contract and the exporter: - Workouts export at all (F1). Every HKWorkout conversion used to be refused: its segment children claimed only grove-mobile-workout-segment, which the HealthKit conversion Provenance does not govern. The pinned guide defines no HealthKit segment output, so a workout now exports its session alone, under output role workout and discriminator single, with the full graph context. Its events and activities are withheld (field dispositions say so), segment construction and the assembler's hasMember hook are deleted, and the retraction of a workout names exactly that session output. New goldens: workout-session, retraction-workout. - Document graphs under a distinct gateway application (F2) no longer carry a gateway Device that nothing references (mobile-support.connected); the guide defines the gateway link for Observations only. - Event instants (F7) — Bundle.timestamp, Provenance.recorded and occurred, DocumentReference.date and every retraction instant — are written by ExchangeInstant: UTC, millisecond precision, ASCII digits, no binary64 noise. A retraction start before 0001-01-01 is stated as that instant. Whole-second instants are byte-identical. - A recording document carries no writer-record identifier (F10, part 1): the version that must travel with it has no carrier on a DocumentReference. This undoes a regression the shared assembler introduced; the sync pair is still validated. - The validator applies the kit's whole adapter-provenance-graph rule (F11): every adapter output is covered by exactly one conversion Provenance of its adapter, checked last as the kit does. - RolePolicy.gatewayForOwnWrites (F3) states the converting application as gateway only for samples written by the build it runs (bundle identifier and HKSourceRevision.version equal to its build). Merging a self-written sample's writer Device into the converter's needs a guide change first: the pinned mapping requires the writer to state the revision version itself. - Retraction (F8, simple policy): a workout-route deletion is retracted only while Options.route is .authorized; an undisclosed route was never exported, and retracting it would disclose that it existed. Outcomes now arrive in input order. All 40 earlier goldens are byte-identical; SensorKit and Questionnaire suites pass. Co-Authored-By: Claude Opus 5.5 --- .../ExchangeGraph+EventPolicy.swift | 1 + .../ExchangeGraph+Profiles.swift | 94 +++- Sources/GroveFHIRContract/ExchangeGraph.swift | 3 + .../ExchangeGraphAssembler+Devices.swift | 21 +- .../ExchangeGraphAssembler.swift | 15 +- .../ExchangeGraphDraft.swift | 4 - .../GroveFHIRContract/ExchangeInstant.swift | 3 + .../GroveFHIRContract/RetractionEvent.swift | 11 +- .../HealthKitAssembly.swift | 24 +- .../HealthKitCatalog+FieldDispositions.swift | 2 +- .../GroveHealthKitFHIR/HealthKitCatalog.swift | 6 +- .../HealthKitConverter+WorkoutSegments.swift | 178 -------- .../HealthKitFHIRExporter+Options.swift | 9 +- .../HealthKitFHIRExporter+Retraction.swift | 31 +- .../HealthKitFHIRExporter.swift | 2 +- .../ConversionThroughputBenchmark.swift | 7 - .../ExchangeEnvelopeFixTests.swift | 142 ++++++ .../GoldenGraphCases+Documents.swift | 7 + .../GoldenGraphCases.swift | 6 + .../GoldenGraphTests.swift | 20 +- .../HealthKitFHIRExporterTests.swift | 11 +- .../Resources/Goldens/outlines.json | 66 +++ .../Resources/Goldens/retraction-workout.json | 133 ++++++ .../Resources/Goldens/workout-session.json | 406 ++++++++++++++++++ 24 files changed, 934 insertions(+), 268 deletions(-) delete mode 100644 Sources/GroveHealthKitFHIR/HealthKitConverter+WorkoutSegments.swift create mode 100644 Tests/GroveHealthKitFHIRTests/ExchangeEnvelopeFixTests.swift create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/retraction-workout.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/workout-session.json diff --git a/Sources/GroveFHIRContract/ExchangeGraph+EventPolicy.swift b/Sources/GroveFHIRContract/ExchangeGraph+EventPolicy.swift index 8c818e316..67511f4a8 100644 --- a/Sources/GroveFHIRContract/ExchangeGraph+EventPolicy.swift +++ b/Sources/GroveFHIRContract/ExchangeGraph+EventPolicy.swift @@ -148,6 +148,7 @@ extension ExchangeGraph { } try validateStudyContext(entries: entries, document: document) try validateSupportingConnectivity(entries: entries, document: document) + try validateAdapterProvenanceGraph(provenance, sourceEntity: sourceEntity, entries: entries, document: document) } private static func validatedActiveProvenance( diff --git a/Sources/GroveFHIRContract/ExchangeGraph+Profiles.swift b/Sources/GroveFHIRContract/ExchangeGraph+Profiles.swift index 2e47b62fa..0c25f5354 100644 --- a/Sources/GroveFHIRContract/ExchangeGraph+Profiles.swift +++ b/Sources/GroveFHIRContract/ExchangeGraph+Profiles.swift @@ -16,6 +16,15 @@ import ModelsR4 extension ExchangeGraph { + /// Every adapter conversion claim in the pinned catalog's `adapterConversionProvenanceClaims` order, with the adapter + /// output profiles its Provenance governs. The generator lists the source-neutral profile first, which has no targets. + static let adapterConversionClaims: [(provenanceProfile: String, outputProfiles: Set)] = + canonicalStrings(ProfileClaims.activeProvenanceProfiles).compactMap { profile in + ProfileClaims.adapterProvenanceTargetProfiles[profile].map { + (provenanceProfile: profile, outputProfiles: Set(canonicalStrings($0))) + } + } + static func validateActiveProfileClaims( entries: [BundleEntry], document: ValidationDocument @@ -31,7 +40,6 @@ extension ExchangeGraph { } if let activeProvenance { try validateDataOriginAgent(activeProvenance) - try validateAdapterProvenanceTargets(activeProvenance, entries: entries) } } @@ -219,35 +227,79 @@ extension ExchangeGraph { } } - static func validateAdapterProvenanceTargets( + /// `mobile-exchange.adapter-provenance-graph` as the pinned kit decides it (graphs.py). Per adapter claim, in catalog + /// order, the entries claiming one of its output profiles are grouped by their one source-record identity. Each group + /// needs the event's Provenance to claim that adapter's conversion profile (else `Bundle.entry`) and to target exactly + /// the group (else `Provenance.target`); an adapter Provenance without a group fails at `Provenance.entity`. + /// + /// Runs last, where the kit runs it (exchange_bundle.py:521): the sole Provenance, the source marker, the targets and + /// the source entity are already valid, so one set comparison stands for the kit's per-target branches. A port of the + /// kit's checks at :518-520 goes before this call; a port of its checks at :614-776 goes after it. + static func validateAdapterProvenanceGraph( _ provenance: Provenance, - entries: [BundleEntry] + sourceEntity: RoledIdentifier, + entries: [BundleEntry], + document: ValidationDocument ) throws(ExchangeGraphError) { - guard let provenanceProfile = canonicalStrings(provenance.meta?.profile ?? []).first, - let admittedProfiles = ProfileClaims.adapterProvenanceTargetProfiles[provenanceProfile] - else { - return + var profiles: [Set] = [] + var governed: Set = [] + for (index, entry) in entries.enumerated() { + profiles.append(try directProfiles(at: index, document: document)) + if case .provenance? = entry.resource { + governed = profiles[index] + } } - let admitted = Set(canonicalStrings(admittedProfiles)) - let resourcePairs: [(String, ResourceProxy)] = entries.compactMap { entry in - guard let fullURL = entry.fullUrl?.value?.url.absoluteString, - let resource = entry.resource else { - return nil + let targets = Set(provenance.target.compactMap { $0.reference?.value?.string }) + for claim in adapterConversionClaims { + let governs = governed.contains(claim.provenanceProfile) + let groups = try adapterOutputGroups(claim.outputProfiles, profiles: profiles, entries: entries, document: document) + for group in groups { + guard governs, group.source == sourceEntity else { + throw diagnostic(.mobileExchangeAdapterProvenanceGraph, location: "Bundle.entry") + } + guard targets == group.fullURLs else { + throw diagnostic(.mobileExchangeAdapterProvenanceGraph, location: "Provenance.target") + } } - return (fullURL, resource) - } - let resourcesByFullURL = [String: ResourceProxy]( - uniqueKeysWithValues: resourcePairs - ) - for target in provenance.target { - guard let reference = target.reference?.value?.string, - let resource = resourcesByFullURL[reference], - !admitted.isDisjoint(with: Set(resourceProfiles(resource))) else { + if governs, !groups.contains(where: { $0.source == sourceEntity }) { throw diagnostic(.mobileExchangeAdapterProvenanceGraph, location: "Provenance.entity") } } } + /// The entries claiming any of `outputProfiles`, grouped by their one typed source-record identity, in entry order. + private static func adapterOutputGroups( + _ outputProfiles: Set, + profiles: [Set], + entries: [BundleEntry], + document: ValidationDocument + ) throws(ExchangeGraphError) -> [(source: RoledIdentifier, fullURLs: Set)] { + var groups: [(source: RoledIdentifier, fullURLs: Set)] = [] + for (index, entry) in entries.enumerated() where !profiles[index].isDisjoint(with: outputProfiles) { + let records = ((try? document.typedResourceIdentifiers(at: index)) ?? []).filter { $0.role == .sourceRecord } + guard records.count == 1, let fullURL = entry.fullUrl?.value?.url.absoluteString else { + // The kit fails this without a rule (graphs.py:30-38), so it reports mobile-exchange.unclassified. + throw .invalidEntries("An adapter-profiled entry carries no single typed source-record identity") + } + if let existing = groups.firstIndex(where: { $0.source == records[0] }) { + groups[existing].fullURLs.insert(fullURL) + } else { + groups.append((source: records[0], fullURLs: [fullURL])) + } + } + return groups + } + + /// The entry resource's `meta.profile` exactly as written, read from the parsed Bundle as the kit reads it. + private static func directProfiles(at index: Int, document: ValidationDocument) throws(ExchangeGraphError) -> Set { + do { + let object = try document.resourceObject(at: index) as? [String: Any] + return Set((object?["meta"] as? [String: Any])?["profile"] as? [String] ?? []) + } catch { + throw .invalidEntries(String(reflecting: type(of: error))) + } + } + /// A Health Connect conversion names its data origin as one identifier-only enterer Device agent. static func validateDataOriginAgent(_ provenance: Provenance) throws(ExchangeGraphError) { guard provenance.meta?.profile?.contains(Profile.healthConnectConversionProvenance) == true else { diff --git a/Sources/GroveFHIRContract/ExchangeGraph.swift b/Sources/GroveFHIRContract/ExchangeGraph.swift index 1b927e798..606bb1b77 100644 --- a/Sources/GroveFHIRContract/ExchangeGraph.swift +++ b/Sources/GroveFHIRContract/ExchangeGraph.swift @@ -86,6 +86,9 @@ public struct ExchangeGraph: Sendable { /// Re-validates stored or received JSON before it is trusted again, and keeps exactly those bytes as ``json``. /// + /// It applies every structural rule a built graph passes, including that each adapter output has exactly one conversion + /// Provenance of its adapter; StructureDefinition and terminology conformance is the conformance lane's to prove. + /// /// Serialized checks run first, because Foundation keeps only one of duplicate members and /// decoding through `Foundation.URL` could normalize an identity system or collapse a /// prohibited resource type before the model sees it. diff --git a/Sources/GroveFHIRContract/ExchangeGraphAssembler+Devices.swift b/Sources/GroveFHIRContract/ExchangeGraphAssembler+Devices.swift index 243c7eb20..f370469b3 100644 --- a/Sources/GroveFHIRContract/ExchangeGraphAssembler+Devices.swift +++ b/Sources/GroveFHIRContract/ExchangeGraphAssembler+Devices.swift @@ -58,7 +58,20 @@ extension ExchangeGraphAssembler { } func resolveDevices(for draft: ExchangeGraphDraft) throws -> Devices { - let converter = try converterSnapshots(event: draft.event, repositoryIDs: draft.repositoryIDs, role: draft.converterRole) + // The guide defines observation-gatewayDevice for Observations only; a gateway snapshot that no + // Observation names would connect to nothing (mobile-support.connected). + let statesGateway = draft.outputs.contains { output in + guard case .observation = output.resource else { + return false + } + return output.links.contains(.gateway) + } + let converter = try converterSnapshots( + event: draft.event, + repositoryIDs: draft.repositoryIDs, + role: draft.converterRole, + statesGateway: statesGateway + ) let recording = try recordingSnapshot(draft.recordingDevice, event: draft.event, repositoryIDs: draft.repositoryIDs) let writer = try writerSnapshots(draft.writer, event: draft.event, repositoryIDs: draft.repositoryIDs, converter: converter) if draft.repositoryIDs[.recordingDevice] != nil, recording == nil { @@ -82,7 +95,8 @@ extension ExchangeGraphAssembler { private func converterSnapshots( event: ExchangeEventIdentifier, repositoryIDs: [ExchangeGraphNode: RepositoryID], - role: ConverterRole + role: ConverterRole, + statesGateway: Bool ) throws -> ConverterSnapshots { let host = try hostSnapshot(envelope.host, event: event, repositoryID: repositoryIDs[.hostDevice]) let application = try applicationSnapshot( @@ -98,6 +112,9 @@ extension ExchangeGraphAssembler { case .gateway: return ConverterSnapshots(host: host, application: application, applicationURL: applicationURL, gateway: nil, gatewayURL: applicationURL) case .gatewayApplication(let gatewayApplication): + guard statesGateway else { + return ConverterSnapshots(host: host, application: application, applicationURL: applicationURL, gateway: nil, gatewayURL: nil) + } let gateway = try applicationSnapshot(gatewayApplication, event: event, parentURL: nil, repositoryID: nil) return ConverterSnapshots( host: host, diff --git a/Sources/GroveFHIRContract/ExchangeGraphAssembler.swift b/Sources/GroveFHIRContract/ExchangeGraphAssembler.swift index c1aacdaeb..5fa442dda 100644 --- a/Sources/GroveFHIRContract/ExchangeGraphAssembler.swift +++ b/Sources/GroveFHIRContract/ExchangeGraphAssembler.swift @@ -121,7 +121,7 @@ package struct ExchangeGraphAssembler: Sendable { entry: entries, identifier: draft.event.identifier.fhirIdentifier, meta: Meta(profile: [Profile.groveMobileExchangeBundle]), - timestamp: FHIRPrimitive(try Instant(utc: draft.instant)), + timestamp: FHIRPrimitive(try ExchangeInstant.fhirInstant(draft.instant)), type: FHIRPrimitive(.collection) ) bundle.id = draft.repositoryIDs[.bundle]?.primitive @@ -154,7 +154,7 @@ extension ExchangeGraphAssembler { value: .coding(Coding(code: "manual-entry", display: "Manual entry", system: Canonicals.recordingMethodCodeSystem)) ) - /// Every output with its identities and links applied; in-graph members are linked from the primary. + /// Every output with its identities and links applied; a derived child names the primary it derives from. private func decoratedOutputs(of draft: ExchangeGraphDraft, surroundings: Surroundings) throws -> [DecoratedOutput] { var outputs: [DecoratedOutput] = [] for (index, output) in draft.outputs.enumerated() { @@ -167,11 +167,6 @@ extension ExchangeGraphAssembler { outputs[index].resource = .observation(observation) } } - let memberURLs = zip(draft.outputs, outputs).filter { $0.0.memberOfPrimary }.map(\.1.url) - if !memberURLs.isEmpty, case .observation(var observation) = outputs[0].resource { - observation.hasMember = (observation.hasMember ?? []) + memberURLs.map { Reference(reference: $0.asFHIRStringPrimitive()) } - outputs[0].resource = .observation(observation) - } return outputs } @@ -209,7 +204,7 @@ extension ExchangeGraphAssembler { case .document(var document): document.id = repositoryID document.identifier = identifiers - document.date = FHIRPrimitive(try Instant(utc: draft.instant)) + document.date = FHIRPrimitive(try ExchangeInstant.fhirInstant(draft.instant)) decorate(&document, links: output.links, surroundings: surroundings) resource = .document(document) } @@ -299,8 +294,8 @@ extension ExchangeGraphAssembler { )], entity: [entity], meta: Meta(profile: [envelope.adapter.provenanceProfile]), - occurred: .dateTime(FHIRPrimitive(try DateTime(utc: recordedAt))), - recorded: FHIRPrimitive(try Instant(utc: recordedAt)), + occurred: .dateTime(FHIRPrimitive(try ExchangeInstant.fhirDateTime(recordedAt))), + recorded: FHIRPrimitive(try ExchangeInstant.fhirInstant(recordedAt)), target: targetURLs.map { Reference(reference: $0.asFHIRStringPrimitive()) } ) } diff --git a/Sources/GroveFHIRContract/ExchangeGraphDraft.swift b/Sources/GroveFHIRContract/ExchangeGraphDraft.swift index 42ecd9461..889acf7d2 100644 --- a/Sources/GroveFHIRContract/ExchangeGraphDraft.swift +++ b/Sources/GroveFHIRContract/ExchangeGraphDraft.swift @@ -122,8 +122,6 @@ package struct ExchangeOutputDraft: Sendable { package let discriminator: String package var resource: Resource package var links: Links - /// Whether the primary output lists this output under `hasMember`; never set on the primary itself. - package var memberOfPrimary: Bool /// Whether this output states the primary under `derivedFrom`; never set on the primary itself. package var derivedFromPrimary: Bool /// The native artifact a document output carries, named by its registered format code. @@ -138,7 +136,6 @@ package struct ExchangeOutputDraft: Sendable { discriminator: String = "single", resource: Resource, links: Links = .all, - memberOfPrimary: Bool = false, derivedFromPrimary: Bool = false, artifactFormatCode: String? = nil, clearIdentifiers: [Identifier] = [], @@ -149,7 +146,6 @@ package struct ExchangeOutputDraft: Sendable { self.discriminator = discriminator self.resource = resource self.links = links - self.memberOfPrimary = memberOfPrimary self.derivedFromPrimary = derivedFromPrimary self.artifactFormatCode = artifactFormatCode self.clearIdentifiers = clearIdentifiers diff --git a/Sources/GroveFHIRContract/ExchangeInstant.swift b/Sources/GroveFHIRContract/ExchangeInstant.swift index cd111ed07..678f8bd94 100644 --- a/Sources/GroveFHIRContract/ExchangeInstant.swift +++ b/Sources/GroveFHIRContract/ExchangeInstant.swift @@ -27,6 +27,9 @@ package enum ExchangeInstant { /// `Date` counts from 2001-01-01T00:00:00Z; the wire counts from 1970. private static let referenceEpochMilliseconds: Int64 = 978_307_200_000 + /// 0001-01-01T00:00:00Z, the earliest instant a FHIR instant or dateTime can state. + static let earliestStatable = date(millisecondsSinceEpoch: -62_135_596_800_000) + /// The instant as a FHIR `instant` lexeme in UTC. package static func utcLexeme(_ date: Date) -> String { let (days, millisecondOfDay) = floorDivide(millisecondsSinceEpoch(date), by: 86_400_000) diff --git a/Sources/GroveFHIRContract/RetractionEvent.swift b/Sources/GroveFHIRContract/RetractionEvent.swift index 2983b6d58..8a4bdbb83 100644 --- a/Sources/GroveFHIRContract/RetractionEvent.swift +++ b/Sources/GroveFHIRContract/RetractionEvent.swift @@ -104,11 +104,12 @@ public enum RetractionTargetError: Error, Equatable, Sendable { } -/// When the source retracted a record, as precisely as the producer knows it. +/// When the source retracted a record, as precisely as the producer knows it, stated in UTC at millisecond precision. public enum RetractionOccurrence: Hashable, Sendable { /// The source's own deletion time, or the time the producer detected the deletion. case instant(Date) /// Bounds on a deletion time the source does not state: after `start` when known, and no later than `end`. + /// A start before 0001-01-01T00:00:00Z is stated as that instant. case period(start: Date?, end: Date) fileprivate func occurredX() throws(RetractionEventError) -> Provenance.OccurredX { @@ -118,11 +119,11 @@ public enum RetractionOccurrence: Hashable, Sendable { do { switch self { case .instant(let date): - return .dateTime(FHIRPrimitive(try DateTime(utc: date))) + return .dateTime(FHIRPrimitive(try ExchangeInstant.fhirDateTime(date))) case let .period(start, end): return .period(Period( - end: FHIRPrimitive(try DateTime(utc: end)), - start: try start.map { FHIRPrimitive(try DateTime(utc: $0)) } + end: FHIRPrimitive(try ExchangeInstant.fhirDateTime(end)), + start: try start.map { FHIRPrimitive(try ExchangeInstant.fhirDateTime(max($0, ExchangeInstant.earliestStatable))) } )) } } catch { @@ -172,7 +173,7 @@ public struct RetractionEvent: Sendable { let occurredX = try occurred.occurredX() let recorded: Instant do { - recorded = try Instant(utc: context.conversionInstant) + recorded = try ExchangeInstant.fhirInstant(context.conversionInstant) } catch { throw .invalidInstant } diff --git a/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift b/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift index 155557754..73a702695 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift @@ -114,11 +114,9 @@ struct HealthKitAssembly: Sendable { discriminator: output.discriminator, resource: .observation(try HealthKitConverter.observation(for: sample, binding: binding)) ) - var outputs = [primary] - if let workout = sample as? HKWorkout { - outputs += try HealthKitConverter.workoutSegments(workout) - } - return HealthKitConversionSet(primary: try graph(for: sample, type: type, outputs: outputs, request: request)) + // A workout exports its session alone: the pinned guide defines no HealthKit segment output, and a + // deletion could not name segments it never saw (healthkit-adapter.json workout row). + return HealthKitConversionSet(primary: try graph(for: sample, type: type, outputs: [primary], request: request)) } /// One source record's graph: the outputs under the sample's envelope, with what the graph does not carry. @@ -132,8 +130,12 @@ struct HealthKitAssembly: Sendable { let facts = try SourceFacts(sample, options: request.options) var outputs = outputs outputs[0].clearIdentifiers = facts.nativeIdentifiers - outputs[0].writerRecord = facts.writerRecord outputs[0].wasUserEntered = facts.wasUserEntered + // A writer-record identity travels only with its version, and only an Observation carries the version + // extension; a document states neither, though the pair is still validated. + if case .observation = outputs[0].resource { + outputs[0].writerRecord = facts.writerRecord + } let draft = ExchangeGraphDraft( event: request.event, instant: request.instant, @@ -177,6 +179,16 @@ struct HealthKitAssembly: Sendable { @available(iOS 18, macOS 15, watchOS 11, *) extension HealthKitAssembly { + /// Whether `revision` names `application` in the build it states: the same bundle identifier, and an + /// `HKSourceRevision.version` (HealthKit copies the source's `CFBundleVersion`) equal to `application.build`. + /// An application that states no build, or a revision without a version, never matches. + static func isSameBuild(_ revision: HKSourceRevision, as application: ApplicationDevice) -> Bool { + guard let build = application.build, let version = revision.version?.nonBlank else { + return false + } + return version == build && revision.source.bundleIdentifier == application.bundleIdentifier + } + /// The event context a retraction or a bundled study context is minted from. func eventContext(for request: Request) -> ExchangeEventContext { ExchangeEventContext( diff --git a/Sources/GroveHealthKitFHIR/HealthKitCatalog+FieldDispositions.swift b/Sources/GroveHealthKitFHIR/HealthKitCatalog+FieldDispositions.swift index 7b358d1c6..9ae9cf304 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitCatalog+FieldDispositions.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitCatalog+FieldDispositions.swift @@ -62,7 +62,7 @@ extension HealthKitCatalog { case .workout: fields.merge([ "workoutActivityType": .carried, "duration": .carried, "statistics": .carried, - "workoutEvents": .carried, "workoutActivities": .carried + "workoutEvents": .withheld, "workoutActivities": .withheld ]) { _, new in new } case .bloodPressure: fields["objects"] = .carried diff --git a/Sources/GroveHealthKitFHIR/HealthKitCatalog.swift b/Sources/GroveHealthKitFHIR/HealthKitCatalog.swift index 7dc675520..d36259f52 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitCatalog.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitCatalog.swift @@ -146,8 +146,7 @@ public enum HealthKitCatalog { /// Every output the converter mints for one source type, in the order the graph emits them. /// /// A caller holding only a source type — a deletion, whose sample is already gone — names - /// the exact outputs an addition minted. Workout segments are absent: their discriminators come - /// from the deleted sample's own events. + /// the exact outputs an addition minted. public static func outputs(for type: HealthKitSourceType) -> [HealthKitOutput] { switch type { case .electrocardiogram: @@ -176,10 +175,9 @@ public enum HealthKitCatalog { guard let binding = binding(forSourceTypeIdentifier: type.rawValue) else { return [] } - // A workout's session totals share their source record with the segments hanging off it. let output = HealthKitOutput( role: binding.contract.id, - discriminator: type == .workout ? "session" : "single", + discriminator: "single", resourceType: .observation, retractionRole: .primaryOutput ) diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+WorkoutSegments.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+WorkoutSegments.swift deleted file mode 100644 index ee9b39e4f..000000000 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+WorkoutSegments.swift +++ /dev/null @@ -1,178 +0,0 @@ -// -// This source file is part of the Grove open-source project -// -// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) -// -// SPDX-License-Identifier: MIT -// - -#if canImport(HealthKit) - -import Foundation -import GroveFHIRContract -import HealthKit -import ModelsR4 - - -@available(iOS 18, macOS 15, watchOS 11, *) -extension HealthKitConverter { - /// The structural intervals a workout carries beyond its session totals. - /// - /// A workout is not one undifferentiated interval: it carries laps, pauses, and — since iOS 16 — - /// per-activity intervals that describe a multi-sport session. Converting only the totals turns a - /// triathlon into a single Observation, so each is emitted as its own segment linked from the - /// session through `hasMember`. - static func workoutSegments(_ workout: HKWorkout) throws -> [ExchangeOutputDraft] { - let sourceTimeZone = try sourceTimeZone(metadata: workout.metadata ?? [:]) - var segments: [ExchangeOutputDraft] = [] - var eventOccurrences: [String: Int] = [:] - for event in workout.workoutEvents ?? [] { - let coordinate = try segmentCoordinate( - kind: "event-\(segmentCode(for: event.type))", - interval: event.dateInterval - ) - let occurrence = eventOccurrences[coordinate, default: 0] - eventOccurrences[coordinate] = occurrence + 1 - segments.append(segment( - discriminator: "\(coordinate):\(occurrence)", - observation: segmentObservation( - value: segmentValue(for: event.type), - effective: try effectivePeriod( - start: event.dateInterval.start, - end: event.dateInterval.end, - sourceTimeZone: sourceTimeZone - ), - components: [], - sourceTypeIdentifier: workout.sampleType.identifier - ) - )) - } - var activityOccurrences: [String: Int] = [:] - for activity in workout.workoutActivities { - // An activity that has not ended has no closed interval, and the profile requires one. - guard let end = activity.endDate else { - continue - } - let interval = DateInterval(start: activity.startDate, end: end) - let coordinate = try segmentCoordinate( - kind: "activity-\(activity.workoutConfiguration.activityType.rawValue)", - interval: interval - ) - let occurrence = activityOccurrences[coordinate, default: 0] - activityOccurrences[coordinate] = occurrence + 1 - segments.append(segment( - discriminator: "\(coordinate):\(occurrence)", - observation: segmentObservation( - value: try workoutValue(activityType: activity.workoutConfiguration.activityType), - effective: try effectivePeriod(start: activity.startDate, end: end, sourceTimeZone: sourceTimeZone), - components: try activityComponents(activity), - sourceTypeIdentifier: workout.sampleType.identifier - ) - )) - } - return segments - } - - /// Stable source coordinates keep child identities invariant when HealthKit reorders arrays. - /// Only exact duplicate coordinates receive an occurrence suffix; those records are otherwise - /// indistinguishable under the published workout-segment contract. - private static func segmentCoordinate(kind: String, interval: DateInterval) throws -> String { - let start = interval.start.timeIntervalSince1970 - let end = interval.end.timeIntervalSince1970 - guard start.isFinite, end.isFinite, end >= start else { - throw HealthKitValueFailure.effectivePeriodInvalid - } - return "\(kind):\(String(groveFHIRPlainDecimal: start)):\(String(groveFHIRPlainDecimal: end))" - } - - /// A segment hangs off the session as a `hasMember` child and states only its subject. - private static func segment(discriminator: String, observation: Observation) -> ExchangeOutputDraft { - ExchangeOutputDraft( - role: "workout-segment", - discriminator: discriminator, - resource: .observation(observation), - links: [.subject], - memberOfPrimary: true - ) - } - - private static func segmentObservation( - value: CodeableConcept, - effective: Period, - components: [ObservationComponent], - sourceTypeIdentifier: String - ) -> Observation { - var observation = Observation( - code: CodeableConcept(coding: [ - Coding( - code: "workout-segment", - system: Canonicals.mobileMeasurementCodeSystem - ) - ]), - status: FHIRPrimitive(.final) - ) - applySourceTypeLineage(sourceTypeIdentifier, to: &observation) - observation.meta = Meta(profile: [Profile.groveMobileWorkoutSegment]) - observation.effective = .period(effective) - observation.value = .codeableConcept(value) - observation.component = components.isEmpty ? nil : components - return observation - } - - /// The structural classification the segment vocabulary publishes for a workout event. - static func segmentValue(for type: HKWorkoutEventType) -> CodeableConcept { - let code = segmentCode(for: type) - return CodeableConcept(coding: [ - Coding( - code: FHIRPrimitive(FHIRString(stringLiteral: code)), - system: Canonicals.workoutSegmentTypeCodeSystem - ) - ]) - } - - private static func segmentCode(for type: HKWorkoutEventType) -> String { - switch type { - case .pause: "pause" - case .resume: "resume" - case .lap: "lap" - case .marker: "marker" - case .motionPaused: "motion-paused" - case .motionResumed: "motion-resumed" - case .segment: "segment-generic" - case .pauseOrResumeRequest: "pause-or-resume-request" - // A case this SDK does not know is classified rather than dropped: the interval it marks is - // still a real interval, and refusing the whole workout over it would lose the session. - @unknown default: "unknown" - } - } - - /// The statistics an activity reports for its own interval, using the session's component codes. - /// - /// An activity that never collected a statistic reports nothing for it, which is absent rather - /// than zero — the same distinction the session totals make. - private static func activityComponents(_ activity: HKWorkoutActivity) throws -> [ObservationComponent] { - let statistics: [WorkoutStatistic] = [ - WorkoutStatistic(componentID: "active-energy-sum", identifier: .activeEnergyBurned, unit: .kilocalorie()), - WorkoutStatistic(componentID: "step-count-sum", identifier: .stepCount, unit: .count()), - WorkoutStatistic(componentID: "flights-climbed-sum", identifier: .flightsClimbed, unit: .count()), - WorkoutStatistic( - componentID: "swimming-stroke-count-sum", - identifier: .swimmingStrokeCount, - unit: .count() - ) - ] - var components: [ObservationComponent] = [] - for statistic in statistics { - guard let quantity = activity.statistics(for: HKQuantityType(statistic.identifier)), - let total = quantity.sumQuantity() else { - continue - } - components.append(try component( - statistic.componentID, - value: total.doubleValue(for: statistic.unit) - )) - } - return components - } -} -#endif diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift index 76dc56e3b..cfe59b3f0 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift @@ -105,8 +105,9 @@ extension HealthKitFHIRExporter { public enum RolePolicy: Hashable, Sendable { /// The application assembled graphs from records it did not mediate. case assembler - /// Samples this application wrote itself (the source bundle identifier equals the application's) - /// are stated as mediated by it; every other sample is merely assembled. + /// Samples this application wrote itself in the build it runs (the source bundle identifier equals the + /// application's and the revision's version equals its build) are stated as mediated by it; every other + /// sample is merely assembled. case gatewayForOwnWrites /// The converting application mediated every measurement. case gateway @@ -114,12 +115,12 @@ extension HealthKitFHIRExporter { case gatewayApplication(ApplicationDevice) /// The role for one sample under this policy. - func converterRole(for source: HKSource, application: ApplicationDevice) -> ConverterRole { + func converterRole(for revision: HKSourceRevision, application: ApplicationDevice) -> ConverterRole { switch self { case .assembler: .assembler case .gatewayForOwnWrites: - source.bundleIdentifier == application.bundleIdentifier ? .gateway : .assembler + HealthKitAssembly.isSameBuild(revision, as: application) ? .gateway : .assembler case .gateway: .gateway case .gatewayApplication(let gateway): diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift index cf75a598a..79b326b5e 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift @@ -15,22 +15,23 @@ import HealthKit @available(iOS 18, macOS 15, watchOS 11, *) extension HealthKitFHIRExporter { - /// Retracts deleted records in input order, one retraction event per deletion whose source type - /// ever emits outputs. Targets are recomputed from the catalog, so nothing from the original - /// export needs to be kept. Errors from the sequencer's storage and from `receive` end the call. + /// Retracts deleted records in input order, one retraction event per deletion that names outputs this + /// exporter can have emitted; every other deletion is reported as ``Export/Outcome/nothingToRetract``. + /// Targets are recomputed from the catalog, so nothing from the original export needs to be kept. + /// Errors from the sequencer's storage and from `receive` end the call. public func retract( _ deletions: some Collection, at instant: Date = .now, receive: (Export) throws -> Void ) throws -> Receipt { - let retractable = deletions.filter { !HealthKitCatalog.outputs(for: $0.sourceType).isEmpty } - let keys = retractable.map(ExchangeEventKey.retraction) - let reservations = keys.isEmpty ? [] : try producer.sequencer.reserve(keys, at: instant) + let keys = deletions.filter(isRetractable).map(ExchangeEventKey.retraction) + var reservations = (keys.isEmpty ? [] : try producer.sequencer.reserve(keys, at: instant)).makeIterator() let producerInstance = keys.isEmpty ? UUID() : try producer.sequencer.producerInstance - for deletion in deletions where HealthKitCatalog.outputs(for: deletion.sourceType).isEmpty { - try receive(Export(source: deletion.source, outcome: .nothingToRetract, warnings: [])) - } - for (deletion, reservation) in zip(retractable, reservations) { + for deletion in deletions { + guard isRetractable(deletion), let reservation = reservations.next() else { + try receive(Export(source: deletion.source, outcome: .nothingToRetract, warnings: [])) + continue + } let outcome: Export.Outcome do { outcome = .graph(try retraction(of: deletion, reservation: reservation, producerInstance: producerInstance)) @@ -43,6 +44,16 @@ extension HealthKitFHIRExporter { return Receipt(keys: keys, sequencer: producer.sequencer) } + /// Whether a deletion names outputs this exporter can have emitted. A type without outputs never emitted any, + /// and a workout route is exported only under ``Options/route`` `.authorized`: retracting an undisclosed route + /// would name a node that never existed and disclose that the route did. + private func isRetractable(_ deletion: Deletion) -> Bool { + guard !HealthKitCatalog.outputs(for: deletion.sourceType).isEmpty else { + return false + } + return deletion.sourceType != .workoutRoute || options.route == .authorized + } + private func retraction( of deletion: Deletion, reservation: ExchangeEventReservation, diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift index f26afcdf9..29c837a5a 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift @@ -205,7 +205,7 @@ extension HealthKitFHIRExporter { sequence: reservation.sequence ), instant: reservation.instant, - converterRole: options.role.converterRole(for: source, application: producer.application), + converterRole: options.role.converterRole(for: sample.sourceRevision, application: producer.application), repositoryIDs: try legacyRepositoryIDs(for: sample.uuid), options: HealthKitConversionOptions( writer: options.writer.classification(of: source), diff --git a/Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark.swift b/Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark.swift index 93be58d5a..f1f121b47 100644 --- a/Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark.swift +++ b/Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark.swift @@ -186,13 +186,6 @@ struct ConversionThroughputBenchmark { )) print("BENCH diagnose withEvents=\(withEvents) type=\(type.rawValue) role=\(output.role)/\(output.discriminator) " + "primaryProfiles=\(profiles) admittedCount=\(admitted.count) primaryAdmitted=\(!admitted.isDisjoint(with: profiles))") - let workout = try #require(sample as? HKWorkout) - let segments = try HealthKitConverter.workoutSegments(workout) - for case .observation(let segment) in segments.prefix(1).map(\.resource) { - let segmentProfiles = ExchangeGraph.canonicalStrings(segment.meta?.profile ?? []) - print("BENCH diagnose segments=\(segments.count) segmentProfiles=\(segmentProfiles) " - + "segmentAdmitted=\(!admitted.isDisjoint(with: segmentProfiles))") - } do { _ = try HealthKitConverter().convert(sample, context: context) print("BENCH diagnose withEvents=\(withEvents) convert=OK") diff --git a/Tests/GroveHealthKitFHIRTests/ExchangeEnvelopeFixTests.swift b/Tests/GroveHealthKitFHIRTests/ExchangeEnvelopeFixTests.swift new file mode 100644 index 000000000..921aad8c8 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ExchangeEnvelopeFixTests.swift @@ -0,0 +1,142 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit +import ModelsR4 +import Testing + + +/// The envelope rules the pinned guide states and the first assembler missed: what a document graph +/// carries, how event instants are written, and which deletions a route policy lets the exporter retract. +@Suite +struct ExchangeEnvelopeFixTests { + private static let base = ExchangeEventContext.test() + + private static func exporter( + application: ApplicationDevice = base.application, + _ configure: (inout HealthKitFHIRExporter.Options) -> Void = { _ in } + ) throws -> HealthKitFHIRExporter { + let producer = try ExchangeProducer( + identityScope: base.identityScope, + subject: base.subject, + application: application, + host: base.host, + sequencer: .inMemory() + ) + var options = HealthKitFHIRExporter.Options() + configure(&options) + return try HealthKitFHIRExporter(producer: producer, repositoryScope: base.repositoryScope, options: options) + } + + private static func heartbeatSeries(uuid ordinal: UInt8) throws -> HealthKitHeartbeatSeriesRecord { + let series = try StoredSampleFixtures.seriesSample( + HKHeartbeatSeriesSample.self, + sampleType: HKSeriesType.heartbeat(), + shape: GoldenCase.seriesShape(uuid: ordinal, duration: 2) + ) + return HealthKitHeartbeatSeriesRecord(series: series, heartbeats: [ + HealthKitHeartbeat(timeSinceSeriesStart: 0, precededByGap: false), + HealthKitHeartbeat(timeSinceSeriesStart: 0.84, precededByGap: false) + ]) + } + + @Test("A document graph under a distinct gateway application carries no gateway Device, as Observations alone name one") + @available(*, deprecated, message: "Exercises the deprecated converter's document path") + func documentGraphsOmitTheGatewayApplication() throws { + let gateway = ApplicationDevice.test(name: "Cuff Companion", bundleIdentifier: "com.example.cuff", version: "3.1") + let context = HealthKitConversionContext(event: .test(converterRole: .gatewayApplication(gateway))) + let conversion = try HealthKitConverter().convert(try Self.heartbeatSeries(uuid: 90), context: context) + let snapshot = try context.identityScope.deviceSnapshot( + event: context.event.event, + role: .application, + sourceDeviceToken: gateway.sourceDeviceToken + ) + #expect(conversion.graph.resource(Device.self, at: snapshot) == nil) + let assembled = try HealthKitConverter().convert(try Self.heartbeatSeries(uuid: 90), context: HealthKitConversionContext()) + #expect(conversion.graph.json == assembled.graph.json) + } + + #if !os(watchOS) + @Test("A document carries no writer-record identifier: the version that must travel with it has no carrier there") + @available(*, deprecated, message: "Exercises the deprecated converter's document path") + func documentsCarryNoWriterRecord() throws { + var metadata = GoldenFixtures.timeZoneMetadata + metadata[HKMetadataKeySyncIdentifier] = "document-1" + metadata[HKMetadataKeySyncVersion] = 3 + let document = try HKCDADocumentSample( + data: Data(GoldenCase.clinicalDocumentXML.utf8), + start: GoldenFixtures.sampleStart, + end: GoldenFixtures.sampleStart.addingTimeInterval(1), + metadata: metadata + ) + let stored = try StoredSampleFixtures.stored(document, uuid: GoldenFixtures.uuid(91), writer: GoldenFixtures.foreignWriter) + let conversion = try HealthKitConverter().convert(stored, context: HealthKitConversionContext()) + let roles = try conversion.document.identifier?.map { try RoledIdentifier($0).role } ?? [] + #expect(!roles.contains(.writerRecord)) + #expect(roles == [.sourceRecord, .sourceOutput, .sourceArtifact]) + } + #endif + + @Test("Event instants are written in UTC at millisecond precision, without binary noise") + @available(*, deprecated, message: "Exercises the deprecated converter, which takes any instant") + func eventInstantsAreMilliseconds() throws { + let context = HealthKitConversionContext(event: .test(conversionInstant: Date(timeIntervalSince1970: 1_787_009_400.2514))) + let conversion = try HealthKitConverter().convert(try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(92)), context: context) + #expect(conversion.bundle.timestamp?.value?.description == "2026-08-17T23:30:00.251Z") + let provenance = try #require(conversion.bundle.entry?.compactMap { $0.resource?.get(if: Provenance.self) }.first) + #expect(provenance.recorded.value?.description == "2026-08-17T23:30:00.251Z") + guard case .dateTime(let occurred)? = provenance.occurred else { + Issue.record("A conversion Provenance occurs at the conversion instant") + return + } + #expect(occurred.value?.description == "2026-08-17T23:30:00.251Z") + } + + @Test("A route deletion is retracted only while routes are disclosed") + func routeRetractionFollowsTheRoutePolicy() throws { + let deletion = HealthKitFHIRExporter.Deletion( + uuid: GoldenFixtures.uuid(93), + sourceType: .workoutRoute, + deletedAfter: nil, + detectedAt: GoldenFixtures.conversionInstant + ) + var omitted: [HealthKitFHIRExporter.Export] = [] + _ = try Self.exporter().retract([deletion], at: GoldenFixtures.conversionInstant) { omitted.append($0) } + guard case .nothingToRetract? = omitted.first?.outcome else { + Issue.record("An undisclosed route was never exported, so there is nothing to retract") + return + } + var authorized: [HealthKitFHIRExporter.Export] = [] + _ = try Self.exporter { $0.route = .authorized }.retract([deletion], at: GoldenFixtures.conversionInstant) { authorized.append($0) } + #expect(authorized.first?.graph?.kind == .retraction) + } + + @Test("Under gatewayForOwnWrites only a sample written by the converting build is mediated by it") + func gatewayForOwnWritesMatchesTheBuild() throws { + let application = GoldenFixtures.selfConverter(version: "1.0", build: "42") + let exporter = try Self.exporter(application: application) { $0.role = .gatewayForOwnWrites } + let sameBuild = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(94), writer: GoldenFixtures.selfWriter(revisionVersion: "42")) + let olderBuild = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(95), writer: GoldenFixtures.selfWriter(revisionVersion: "41")) + var exports: [HealthKitFHIRExporter.Export] = [] + _ = try exporter.export([sameBuild, olderBuild], at: GoldenFixtures.conversionInstant) { exports.append($0) } + func statesGateway(_ export: HealthKitFHIRExporter.Export) -> Bool { + let observation = export.graph?.bundle.entry?.compactMap { $0.resource?.get(if: Observation.self) }.first + return observation?.extension?.contains { $0.url == Canonicals.gatewayDevice } == true + } + try #require(exports.count == 2) + #expect(statesGateway(exports[0])) + #expect(!statesGateway(exports[1])) + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift index cc44a39ec..766ee7d55 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift @@ -105,6 +105,13 @@ extension GoldenCase { context: GoldenFixtures.context(sequence: sequence), occurred: .period(start: nil, end: GoldenFixtures.conversionInstant) )) + }, + GoldenCase("retraction-workout", sequence: 84) { sequence in + GoldenOutput(try HealthKitConverter().retraction( + for: HealthKitSourceRecord(uuid: GoldenFixtures.uuid(84), type: .workout), + context: GoldenFixtures.context(sequence: sequence), + occurred: .instant(GoldenFixtures.conversionInstant) + )) } ] diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift index 056187f4e..c594ef745 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift @@ -111,6 +111,12 @@ extension GoldenCase { GoldenFixtures.quantity(.bodyMass, HKQuantity(unit: .gramUnit(with: .kilo), doubleValue: 71.3), uuid: GoldenFixtures.uuid(13), metadata: metadata), sequence: sequence ) + }, + GoldenCase("workout-session", sequence: 14) { sequence in + try GoldenFixtures.convert( + StoredSampleFixtures.stored(try GoldenFixtures.workout(withEvents: true), uuid: GoldenFixtures.uuid(14)), + sequence: sequence + ) } ] diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift index d76946042..0cf08110b 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift @@ -219,18 +219,20 @@ struct GoldenGraphTests { } } - /// The old converter refuses every `HKWorkout`: its segment children claim a profile the Provenance contract does - /// not admit. Pinned as the refusal it is, so the rework's workout output is a deliberate change, not a silent one. + /// A workout exports its session alone, events or not: one Observation, no members, one Provenance target. + /// (The old converter refused every workout: its segment children claimed a profile the Provenance contract + /// does not admit.) @Test(arguments: [false, true]) - func workoutsAreRefused(withEvents: Bool) throws { + func workoutsExportTheSessionAlone(withEvents: Bool) throws { let workout = try StoredSampleFixtures.stored(try GoldenFixtures.workout(withEvents: withEvents), uuid: GoldenFixtures.uuid(0xA0)) let context = try GoldenFixtures.context(sequence: 200) - let error = #expect(throws: HealthKitConversionError.self) { - try HealthKitConverter().convert(workout, context: context) - } - let diagnostic = try #require(error?.diagnostic) - #expect(diagnostic.code == "mobile-exchange.adapter-provenance-graph") - #expect(diagnostic.location == "Provenance.entity") + let conversion = try HealthKitConverter().convert(workout, context: context) + let observations = conversion.bundle.entry?.compactMap { $0.resource?.get(if: Observation.self) } ?? [] + #expect(observations.count == 1) + #expect(observations.first?.hasMember == nil) + #expect(conversion.primary.identifiers.childOutputs.isEmpty) + let provenance = try #require(conversion.bundle.entry?.compactMap { $0.resource?.get(if: Provenance.self) }.first) + #expect(provenance.target.count == 1) } /// A writer whose bundle identifier is not one is a refusal; a writer with a blank name is merely no writer diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift index 4152fb97b..7e306ca64 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift @@ -236,15 +236,14 @@ struct HealthKitFHIRExporterTests { var exports: [HealthKitFHIRExporter.Export] = [] let receipt = try exporter.retract(deletions, at: detectedAt) { exports.append($0) } try #require(exports.count == 3) - guard case .nothingToRetract = exports[0].outcome else { - Issue.record("a systolic component never emitted outputs; expected nothingToRetract, got \(exports[0].outcome)") + // Outcomes arrive in input order; the systolic component never emitted outputs. + guard case .nothingToRetract = exports[1].outcome else { + Issue.record("a systolic component never emitted outputs; expected nothingToRetract, got \(exports[1].outcome)") return } - #expect(exports[0].source.uuid == GoldenFixtures.uuid(11)) - #expect(exports[1].source.uuid == GoldenFixtures.uuid(10)) - #expect(exports[2].source.uuid == GoldenFixtures.uuid(12)) + #expect(exports.map(\.source.uuid) == [GoldenFixtures.uuid(10), GoldenFixtures.uuid(11), GoldenFixtures.uuid(12)]) let producerInstance = try exporter.producer.sequencer.producerInstance - for (export, sequence, deletion) in [(exports[1], UInt64(1), deletions[0]), (exports[2], 2, deletions[2])] { + for (export, sequence, deletion) in [(exports[0], UInt64(1), deletions[0]), (exports[2], 2, deletions[2])] { let context = HealthKitConversionContext(event: ExchangeEventContext( subject: Self.base.subject, event: try ExchangeEventIdentifier(system: Self.base.identityScope.systems.event, producerInstance: producerInstance, sequence: EventSequence(sequence)), diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json index 33446d279..a25717341 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json @@ -1463,6 +1463,23 @@ ] }, + "retraction-workout" : { + "entries" : [ + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:a433d24d-e9f8-5bdf-8168-45948039015e", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, "sleep-analysis" : { "entries" : [ { @@ -2021,6 +2038,55 @@ ] }, + "workout-session" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:f2c24e14-a44c-5223-885d-e04a901a4810", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:XMPyrHlnB6bEhpTarUSLguqTDwQYjkKCdL7mWGZgctQ", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:xzNbhHDGo4qN9EX4b3FxfIjrCFK2VWAFsbUWuN9Urmg" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:3c74b947-482d-5af3-943d-482c78dff263", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:HXCBy9I1gZKMDLmWnTmAd01csa0akvquNRs1pjR6MRw" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:989c2b30-57e7-5f8a-a608-06377c9f670e", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:amOHxM6H4U1dh1CB49ecihjxqGsbxgDZMJ9wXxDiYdY", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:3def4f4e-b0c2-5200-8095-39656d20cbcb", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, "writer-blank-name-with-sync-identity" : { "entries" : [ { diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/retraction-workout.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/retraction-workout.json new file mode 100644 index 000000000..e2bccc763 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/retraction-workout.json @@ -0,0 +1,133 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:retraction-provenance:0:SqKZPVC9kH1mZ5-jgPpQpqk3nuJe6dHTMvy_Z9wuwzw" + } + } + ], + "fullUrl" : "urn:uuid:a433d24d-e9f8-5bdf-8168-45948039015e", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "source-record-retracted", + "display" : "Source record retracted", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-lifecycle-event" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Bg5J-mAki3Ews6NnoMFEJ2s5zohF9s2HrHuT9FKhm2Y" + }, + "type" : "Device" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:xq8bZw2djKRrLW5zMKlR5IHmu68FOcEBCfnJ_nd90dA" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-retraction-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-retraction-target-role", + "valueCode" : "primary-output" + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:WzCo_d2wDDiFxkCmWZ3Tv1jjeKFIwfK1vc9Rt_LzCts" + }, + "type" : "Observation" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:84" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-retraction-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/workout-session.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/workout-session.json new file mode 100644 index 000000000..1bbd39b46 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/workout-session.json @@ -0,0 +1,406 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:xzNbhHDGo4qN9EX4b3FxfIjrCFK2VWAFsbUWuN9Urmg" + } + } + ], + "fullUrl" : "urn:uuid:f2c24e14-a44c-5223-885d-e04a901a4810", + "resource" : { + "code" : { + "coding" : [ + { + "code" : "workout", + "display" : "Workout session", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement" + } + ] + }, + "component" : [ + { + "code" : { + "coding" : [ + { + "code" : "active-duration", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic" + } + ] + }, + "valueQuantity" : { + "code" : "s", + "system" : "http://unitsofmeasure.org", + "unit" : "s", + "value" : 3540 + } + }, + { + "code" : { + "coding" : [ + { + "code" : "distance-sum", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic" + } + ] + }, + "valueQuantity" : { + "code" : "m", + "system" : "http://unitsofmeasure.org", + "unit" : "m", + "value" : 10000 + } + }, + { + "code" : { + "coding" : [ + { + "code" : "active-energy-sum", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic" + } + ] + }, + "valueQuantity" : { + "code" : "kcal", + "system" : "http://unitsofmeasure.org", + "unit" : "kcal", + "value" : 640 + } + } + ], + "effectivePeriod" : { + "_end" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "Europe/Berlin" + } + ] + }, + "_start" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "Europe/Berlin" + } + ] + }, + "end" : "2026-08-06T10:06:40+02:00", + "start" : "2026-08-06T09:06:40+02:00" + }, + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKWorkoutTypeIdentifier" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:XMPyrHlnB6bEhpTarUSLguqTDwQYjkKCdL7mWGZgctQ" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:xzNbhHDGo4qN9EX4b3FxfIjrCFK2VWAFsbUWuN9Urmg" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueCodeableConcept" : { + "coding" : [ + { + "code" : "running", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity" + }, + { + "code" : "running", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity" + } + ] + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:HXCBy9I1gZKMDLmWnTmAd01csa0akvquNRs1pjR6MRw" + } + } + ], + "fullUrl" : "urn:uuid:3c74b947-482d-5af3-943d-482c78dff263", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:HXCBy9I1gZKMDLmWnTmAd01csa0akvquNRs1pjR6MRw" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:amOHxM6H4U1dh1CB49ecihjxqGsbxgDZMJ9wXxDiYdY" + } + } + ], + "fullUrl" : "urn:uuid:989c2b30-57e7-5f8a-a608-06377c9f670e", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:amOHxM6H4U1dh1CB49ecihjxqGsbxgDZMJ9wXxDiYdY" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:3c74b947-482d-5af3-943d-482c78dff263" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:ckiXBrNsD2PFVxEdJF_eVr-AhmWTbsXCDiMfSmlnDQI" + } + } + ], + "fullUrl" : "urn:uuid:3def4f4e-b0c2-5200-8095-39656d20cbcb", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:989c2b30-57e7-5f8a-a608-06377c9f670e" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:XMPyrHlnB6bEhpTarUSLguqTDwQYjkKCdL7mWGZgctQ" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:f2c24e14-a44c-5223-885d-e04a901a4810" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:14" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file From ffec7fbc6a3121705b4e1d15f6e6843d6481a548 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sat, 3 Oct 2026 21:45:35 +0200 Subject: [PATCH 008/220] Key the Exchange Ledger and Freeze What Each Event States Implements the Grove part of the exchange-ledger design (ledger-design/final-spec.md sections (a), (b), (d) and the Grove tests of (f), steps 1 to 3 and the ledger half of step 5), except the writer policy, which is the next step. Storage and sequencer (GroveFHIRContract): - ExchangeEventSequencer.Storage is a backend-independent, transactional string-to-bytes map (Storage.transaction, Transaction.read/write/remove/keys(prefixedBy:)) with the C1-C5 contract documented in the new ExchangeLedgerStorage article. InMemoryStorage is the public reference implementation; inMemory() uses it. - The ledger keeps three versioned JSON entry kinds: `producer`, `event/` and `facts/`. Every read is validated and faults surface as typed LedgerError (unsupportedEntryVersion, corruptEntry), never a trap; reset() always recovers. - reserve(_:at:facts:) is one transaction over its own keys: a key whose stored fingerprint matches returns its instance, sequence, instant and frozen facts and writes nothing; any other request takes the next sequence (sorted request order) under the current facts. The producer instance is returned with every reservation, and a counter that would overflow mints a new instance. - Holds are tracked in process memory (HoldRegistry); finish(_:released:forgetting:) removes a reservation only when its last live holder finishes and some holder released it, and only while the key still holds that exact (key, instance, sequence). Nothing is pruned implicitly; forgetReservations(madeBefore:) is the explicit maintenance call. - Deleted: State, Retention, StateError, the producerInstance getter, releaseIgnoringErrors, the sequencer lock and the reservation's Codable conformance. - ExchangeEventFacts (application, host, studies) are stored once per distinct value, decoded through the validating initializers, and every graph is built from the decoded entry, first delivery and redelivery alike. ExchangeEnvelope carries them and swaps them per event (with(_:)); the HealthKit assembly builds its assembler per request facts. - OpaqueIdentityScope.ledgerFingerprint, ExchangeGraphAssembler.outputRevision and HealthKitAssembly.outputRevision (both 1) feed the exporter's context fingerprint. Exporter (GroveHealthKitFHIR): - One reserve transaction per export or retraction call. Requests carry an exhaustive context fingerprint (output revisions, identity scope, subject, repository scope, every option by exhaustive switch) plus record parts (an ECG's sorted symptom UUIDs, a retraction's clamped bounds), so a changed context never reuses an identifier. - ECG symptoms are paired with their reservations by request, not by position. - Nothing is released mid-call: refusals and policy omissions keep their reservations until the receipt is released. - Receipt is a final class that releases at most once (also across copies), in one transaction, none when empty; dropped unreleased it lapses. A retraction receipt also forgets each deleted record's active reservation, only on release. - The gateway-for-own-writes role compares against the frozen application build. Docs: a new ExchangeLedgerStorage article (C1-C5, the backend table, cost, holds); the contract and HealthKit recipes now build a producer over the app's ledger, store graph.json verbatim and release the receipt after the cursor commit; the HealthKit catalog lists the exporter and its receipt, and three cross-module symbol links that could not resolve (two pre-existing) are plain code voice. Both modules' DocC builds report no symbol-link warnings. Audit ledger findings addressed: section 2 findings 1 (unfrozen facts), 2 (instance read in a second transaction), 3 (key-only release), 4 (keys not scoped to subject or repository, via the fingerprint), 5 (stored ledger not validated), 6 (implicit retention and the false releaseIgnoringErrors doc), 7 (storage contract), and the recipe part of 11; section 3 findings 4 (two deletions of one record shared an event), 5 (empty receipt opened a transaction), 6 (positional ECG symptom pairing), 7 (export(records:) untested, now through the internal seam) and the Receipt part of 8. Deviations from the design: ledgerFingerprint frames every derived system, not only the event system; a stored producer instance must state an RFC 4122 version, as every event identifier requires; the deprecated converter keeps its positional symptom contexts (HealthKitAssembly.SymptomRequests.positional) so its refusal order is unchanged. Tests: the sequencer and storage-contract tests move to GroveFHIRTests (G1, G5-G10, G12-G15, G18 codec), with CountingStorage, FaultyStorage and a single-file FileStorage; exporter tests G2, G3, G3b, G4, G8-G11, G17, G18, E1 and E2 in GroveHealthKitFHIRTests. The existing exporter tests now read sequences from the graphs, as new keys take sequences in sorted request order, and refusalsDoNotEndTheExport asserts that a refusal holds its reservation. Output unchanged: every golden is byte-identical, verified by GoldenGraphTests and the new G17 digest table at output revision 1. Co-Authored-By: Claude Opus 5.5 --- Package.swift | 1 + .../ExchangeEventFacts.swift | 36 ++ .../GroveFHIRContract/ExchangeEventKey.swift | 50 +-- .../ExchangeEventSequencer+Entries.swift | 212 ++++++++++++ .../ExchangeEventSequencer+Facts.swift | 146 ++++++++ .../ExchangeEventSequencer+Holds.swift | 83 +++++ ...changeEventSequencer+InMemoryStorage.swift | 85 +++++ .../ExchangeEventSequencer+State.swift | 83 ----- .../ExchangeEventSequencer.swift | 268 ++++++++------- .../ExchangeGraphAssembler.swift | 5 + .../ExchangeGraphDraft.swift | 34 +- .../GroveFHIRContract/ExchangeInstant.swift | 2 +- .../GroveFHIRContract/ExchangeProducer.swift | 5 +- .../ExchangeLedgerStorage.md | 88 +++++ .../GroveFHIRContract.md | 35 +- .../GroveFHIRContract/LedgerEntryCoding.swift | 91 +++++ .../OpaqueIdentityEncoding.swift | 3 +- .../OpaqueIdentityScope.swift | 16 + .../GroveHealthKitFHIR.md | 48 ++- .../HealthKitAssembly+Records.swift | 43 ++- .../HealthKitAssembly.swift | 42 ++- .../HealthKitConverter+ECG.swift | 2 +- .../HealthKitFHIRExporter+Fingerprint.swift | 205 +++++++++++ .../HealthKitFHIRExporter+Results.swift | 62 +++- .../HealthKitFHIRExporter+Retraction.swift | 60 ++-- .../HealthKitFHIRExporter.swift | 225 ++++++++---- .../ExchangeLedger/CountingStorage.swift | 89 +++++ .../ExchangeEventHoldTests.swift | 125 +++++++ .../ExchangeEventSequencerTests.swift | 143 ++++++++ .../ExchangeLedgerEntryTests.swift | 253 ++++++++++++++ .../ExchangeLedgerPropertyTests.swift | 159 +++++++++ .../ExchangeLedger/FaultyStorage.swift | 84 +++++ .../ExchangeLedger/FileStorage.swift | 138 ++++++++ .../ExchangeLedger/LedgerFixtures.swift | 76 ++++ .../ExchangeEventSequencerTests.swift | 325 ------------------ .../ExchangeProducerTests.swift | 2 +- .../GoldenGraphCases+Documents.swift | 60 ++-- .../GoldenGraphTests.swift | 2 +- .../GoldenOutputRevisionTests.swift | 114 ++++++ .../HealthKitConverter+TestSeams.swift | 2 +- ...ealthKitFHIRExporterFingerprintTests.swift | 126 +++++++ .../HealthKitFHIRExporterFixtures.swift | 174 ++++++++++ .../HealthKitFHIRExporterLedgerTests.swift | 299 ++++++++++++++++ .../HealthKitFHIRExporterTests.swift | 82 ++--- 44 files changed, 3375 insertions(+), 808 deletions(-) create mode 100644 Sources/GroveFHIRContract/ExchangeEventFacts.swift create mode 100644 Sources/GroveFHIRContract/ExchangeEventSequencer+Entries.swift create mode 100644 Sources/GroveFHIRContract/ExchangeEventSequencer+Facts.swift create mode 100644 Sources/GroveFHIRContract/ExchangeEventSequencer+Holds.swift create mode 100644 Sources/GroveFHIRContract/ExchangeEventSequencer+InMemoryStorage.swift delete mode 100644 Sources/GroveFHIRContract/ExchangeEventSequencer+State.swift create mode 100644 Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md create mode 100644 Sources/GroveFHIRContract/LedgerEntryCoding.swift create mode 100644 Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift create mode 100644 Tests/GroveFHIRTests/ExchangeLedger/CountingStorage.swift create mode 100644 Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldTests.swift create mode 100644 Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventSequencerTests.swift create mode 100644 Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerEntryTests.swift create mode 100644 Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerPropertyTests.swift create mode 100644 Tests/GroveFHIRTests/ExchangeLedger/FaultyStorage.swift create mode 100644 Tests/GroveFHIRTests/ExchangeLedger/FileStorage.swift create mode 100644 Tests/GroveFHIRTests/ExchangeLedger/LedgerFixtures.swift delete mode 100644 Tests/GroveHealthKitFHIRTests/ExchangeEventSequencerTests.swift create mode 100644 Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift create mode 100644 Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFingerprintTests.swift create mode 100644 Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFixtures.swift create mode 100644 Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterLedgerTests.swift diff --git a/Package.swift b/Package.swift index 50b04f9a9..9f8616564 100644 --- a/Package.swift +++ b/Package.swift @@ -841,6 +841,7 @@ var targets: [Target] = [ name: "GroveFHIRTests", dependencies: [ .target(name: "GroveFHIR"), + .target(name: "GroveFHIRContract"), "GroveHealthKitFHIR" ], exclude: testTargetExcludes("GroveFHIRTests", additional: ["UITests"]), diff --git a/Sources/GroveFHIRContract/ExchangeEventFacts.swift b/Sources/GroveFHIRContract/ExchangeEventFacts.swift new file mode 100644 index 000000000..da74e25cb --- /dev/null +++ b/Sources/GroveFHIRContract/ExchangeEventFacts.swift @@ -0,0 +1,36 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +import Foundation + + +/// What an event states about the converting application, its host and the participant's studies, +/// frozen at reservation so an exact redelivery rebuilds identical bytes. +/// +/// Every graph is built from its reservation's facts, which are always decoded from the ledger's stored +/// entry: the first delivery and every redelivery take the same path. +package struct ExchangeEventFacts: Hashable, Sendable { + package let application: ApplicationDevice + package let host: HostDevice + /// The enrollments in graph order. + package let studies: [StudyEnrollment] + + package init(application: ApplicationDevice, host: HostDevice, studies: [StudyEnrollment]) { + self.application = application + self.host = host + self.studies = studies + } +} + + +extension ExchangeProducer { + /// The facts a new reservation is minted under: this producer's, as captured when it was built. + package var facts: ExchangeEventFacts { + ExchangeEventFacts(application: application, host: host, studies: studies) + } +} diff --git a/Sources/GroveFHIRContract/ExchangeEventKey.swift b/Sources/GroveFHIRContract/ExchangeEventKey.swift index 92c4b79e9..bcb43bf6b 100644 --- a/Sources/GroveFHIRContract/ExchangeEventKey.swift +++ b/Sources/GroveFHIRContract/ExchangeEventKey.swift @@ -14,33 +14,41 @@ import Crypto package import Foundation -/// What a key holds while it is reserved: the event's sequence and the instant it was reserved at. -package struct ExchangeEventReservation: Hashable, Codable, Sendable { - private enum CodingKeys: String, CodingKey { - case sequence - case instantMilliseconds +/// One event an exporter needs: its key, and the digest of every input that shapes its graph but is not +/// rebuilt from the frozen facts. Equal requests share one reservation; a stored reservation is reused only +/// for a request with the same fingerprint, so an event identifier never carries different content. +package struct ExchangeEventRequest: Hashable, Sendable { + package let key: ExchangeEventKey + /// SHA-256, base64url without padding; opaque to the sequencer. + package let fingerprint: String + + package init(key: ExchangeEventKey, fingerprint: String) { + self.key = key + self.fingerprint = fingerprint } +} - package let sequence: EventSequence - /// The caller's instant at reservation, at millisecond precision, the same on every return of the key. - package let instant: Date - init(_ stored: ExchangeEventSequencer.State.Reservation) { - self.sequence = EventSequence(stored.sequence) - self.instant = ExchangeInstant.date(millisecondsSinceEpoch: stored.instantMilliseconds) +/// What an event is minted and rebuilt from: its producer instance and sequence, its instant, and the +/// facts it was minted under, all read in the same transaction. +package struct ExchangeEventReservation: Hashable, Sendable { + /// Identifies this exact reservation, so a release never removes a successor's. Unique across ledgers, + /// as every ledger mints its own producer instance. + package struct Handle: Hashable, Sendable { + let key: ExchangeEventKey + let instance: UUID + let sequence: UInt64 } - package init(from decoder: any Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - self.sequence = try EventSequence(container.decode(String.self, forKey: .sequence)) - self.instant = ExchangeInstant.date(millisecondsSinceEpoch: try container.decode(Int64.self, forKey: .instantMilliseconds)) - } + package let handle: Handle + package let sequence: EventSequence + /// The instant of the first reservation, at millisecond precision, the same on every return of the key. + package let instant: Date + /// Always decoded from the ledger's stored facts entry. + package let facts: ExchangeEventFacts - package func encode(to encoder: any Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(sequence.rawValue, forKey: .sequence) - try container.encode(ExchangeInstant.millisecondsSinceEpoch(instant), forKey: .instantMilliseconds) - } + /// The producer instance the sequence was handed out under. + package var producerInstance: UUID { handle.instance } } diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer+Entries.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer+Entries.swift new file mode 100644 index 000000000..ddafd5340 --- /dev/null +++ b/Sources/GroveFHIRContract/ExchangeEventSequencer+Entries.swift @@ -0,0 +1,212 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +import Foundation + + +/// The `producer` entry: the current producer instance and the next sequence it hands out. +struct ProducerEntry: Equatable { + private struct Payload: Codable { + enum CodingKeys: String, CodingKey { + case version = "v" + case instance + case next + } + + let version: Int + let instance: String + let next: String + } + + var instance: UUID + var next: UInt64 + + init(instance: UUID, next: UInt64) { + self.instance = instance + self.next = next + } + + init(decoding value: Data) throws { + let payload = try LedgerEntryCoding.decode(Payload.self, from: value, key: LedgerKey.producer) + guard let instance = LedgerEntryCoding.instance(payload.instance), let next = LedgerEntryCoding.positiveInteger(payload.next) else { + throw ExchangeEventSequencer.LedgerError.corruptEntry(key: LedgerKey.producer) + } + self.init(instance: instance, next: next) + } + + func encoded() throws -> Data { + try LedgerEntryCoding.encode(Payload( + version: LedgerEntryCoding.version, + instance: instance.uuidString.lowercased(), + next: String(next) + )) + } +} + + +/// An `event/` entry: one key's reservation, the facts it was minted under, and the fingerprint of the +/// context that shaped its graph. +struct EventEntry: Equatable { + private struct Payload: Codable { + enum CodingKeys: String, CodingKey { + case version = "v" + case instance + case sequence + case instant + case facts + case fingerprint + } + + let version: Int + let instance: String + let sequence: String + let instant: Int64 + let facts: String + let fingerprint: String + } + + let instance: UUID + let sequence: UInt64 + /// Whole milliseconds since 1970-01-01T00:00:00Z. + let instantMilliseconds: Int64 + /// The digest naming the `facts/` entry. + let facts: String + let fingerprint: String + + init(instance: UUID, sequence: UInt64, instantMilliseconds: Int64, facts: String, fingerprint: String) { + self.instance = instance + self.sequence = sequence + self.instantMilliseconds = instantMilliseconds + self.facts = facts + self.fingerprint = fingerprint + } + + init(decoding value: Data, key: String) throws { + let payload = try LedgerEntryCoding.decode(Payload.self, from: value, key: key) + guard let instance = LedgerEntryCoding.instance(payload.instance), + let sequence = LedgerEntryCoding.positiveInteger(payload.sequence), + LedgerEntryCoding.isDigest(payload.facts) else { + throw ExchangeEventSequencer.LedgerError.corruptEntry(key: key) + } + self.init( + instance: instance, + sequence: sequence, + instantMilliseconds: payload.instant, + facts: payload.facts, + fingerprint: payload.fingerprint + ) + } + + func encoded() throws -> Data { + try LedgerEntryCoding.encode(Payload( + version: LedgerEntryCoding.version, + instance: instance.uuidString.lowercased(), + sequence: String(sequence), + instant: instantMilliseconds, + facts: facts, + fingerprint: fingerprint + )) + } +} + + +extension ExchangeEventReservation { + /// The reservation a stored or newly written event entry describes. + init(key: ExchangeEventKey, entry: EventEntry, facts: ExchangeEventFacts) { + self.init( + handle: Handle(key: key, instance: entry.instance, sequence: entry.sequence), + sequence: EventSequence(entry.sequence), + instant: ExchangeInstant.date(millisecondsSinceEpoch: entry.instantMilliseconds), + facts: facts + ) + } +} + + +extension ExchangeEventSequencer { + /// One `reserve` call inside its transaction: it reads only the entries of its own keys, the producer, + /// and each distinct facts entry once, and writes only what it mints. + struct ReserveTransaction { + private let transaction: any Transaction + private let current: PreparedFacts + private let instantMilliseconds: Int64 + private var factsByDigest: [String: ExchangeEventFacts] = [:] + private var currentFactsStored = false + + init(transaction: any Transaction, current: PreparedFacts, instantMilliseconds: Int64) { + self.transaction = transaction + self.current = current + self.instantMilliseconds = instantMilliseconds + } + + mutating func reserve(_ requests: [ExchangeEventRequest]) throws -> [ExchangeEventRequest: ExchangeEventReservation] { + let stored = try transaction.read(LedgerKey.producer).map { try ProducerEntry(decoding: $0) } + var producer = stored ?? ProducerEntry(instance: UUID(), next: 1) + var minted = false + var reserved: [ExchangeEventRequest: ExchangeEventReservation] = [:] + for request in requests { + let key = LedgerKey.event(request.key) + let event = try transaction.read(key).map { try EventEntry(decoding: $0, key: key) } + // A reservation at or above the counter of its own instance means the counter regressed. + if let event, event.instance == producer.instance, event.sequence >= producer.next { + throw LedgerError.corruptEntry(key: key) + } + if let event, event.fingerprint == request.fingerprint { + reserved[request] = ExchangeEventReservation(key: request.key, entry: event, facts: try facts(event.facts, of: key)) + continue + } + if producer.next == .max { + producer = ProducerEntry(instance: UUID(), next: 1) + } + let entry = EventEntry( + instance: producer.instance, + sequence: producer.next, + instantMilliseconds: instantMilliseconds, + facts: current.digest, + fingerprint: request.fingerprint + ) + producer.next += 1 + minted = true + try storeCurrentFacts() + try transaction.write(try entry.encoded(), for: key) + reserved[request] = ExchangeEventReservation(key: request.key, entry: entry, facts: current.facts) + } + if minted { + try transaction.write(try producer.encoded(), for: LedgerKey.producer) + } + return reserved + } + + /// The facts a stored reservation names, decoded once per call; a missing entry makes the reservation corrupt. + private mutating func facts(_ digest: String, of eventKey: String) throws -> ExchangeEventFacts { + if let facts = factsByDigest[digest] { + return facts + } + let key = LedgerKey.facts(digest) + guard let value = try transaction.read(key) else { + throw LedgerError.corruptEntry(key: eventKey) + } + let facts = try PreparedFacts.decode(value, key: key) + factsByDigest[digest] = facts + currentFactsStored = currentFactsStored || digest == current.digest + return facts + } + + /// Writes the current facts entry once per call, unless the ledger already holds it. + private mutating func storeCurrentFacts() throws { + guard !currentFactsStored else { + return + } + let key = LedgerKey.facts(current.digest) + if try transaction.read(key) == nil { + try transaction.write(current.bytes, for: key) + } + currentFactsStored = true + } + } +} diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer+Facts.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer+Facts.swift new file mode 100644 index 000000000..6a03a1d1a --- /dev/null +++ b/Sources/GroveFHIRContract/ExchangeEventSequencer+Facts.swift @@ -0,0 +1,146 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(CryptoKit) +import CryptoKit +#else +import Crypto +#endif +import Foundation +import ModelsR4 + + +/// One `facts/` entry: the bytes stored, their digest, and the facts decoded back from them. +/// +/// The digest is the SHA-256, base64url without padding, of the entry's bytes, so equal facts share one +/// entry across producer instances; a reservation names its digest, so an encoding that differs on another +/// platform only misses a deduplication. +struct PreparedFacts { + private struct Payload: Codable { + enum CodingKeys: String, CodingKey { + case version = "v" + case application + case host + case studies + } + + let version: Int + let application: ApplicationPayload + let host: HostPayload + let studies: [StudyPayload] + } + + private struct ApplicationPayload: Codable { + let name: String + let bundleIdentifier: String + let version: String + let build: String? + } + + private struct HostPayload: Codable { + let operatingSystemVersion: String + let name: String? + let manufacturer: String? + let modelNumber: String? + } + + private struct IdentifierPayload: Codable { + let system: String + let value: String + } + + private struct StudyPayload: Codable { + let study: IdentifierPayload + /// The canonical as written, `` or `|`; graphs read only its URL. + let protocolURL: String? + let protocolVersion: String + let enrollment: IdentifierPayload + } + + let bytes: Data + let digest: String + /// The facts as every graph sees them: decoded from ``bytes``, never the caller's values. + let facts: ExchangeEventFacts + + init(_ facts: ExchangeEventFacts) throws { + let payload = Payload( + version: LedgerEntryCoding.version, + application: ApplicationPayload( + name: facts.application.name, + bundleIdentifier: facts.application.bundleIdentifier, + version: facts.application.version, + build: facts.application.build + ), + host: HostPayload( + operatingSystemVersion: facts.host.operatingSystemVersion, + name: facts.host.name, + manufacturer: facts.host.manufacturer, + modelNumber: facts.host.modelNumber + ), + studies: facts.studies.map { enrollment in + StudyPayload( + study: IdentifierPayload(system: enrollment.study.system.rawValue, value: enrollment.study.value), + protocolURL: enrollment.protocolURL.value.map { canonical in + canonical.version.map { "\(canonical.url.absoluteString)|\($0)" } ?? canonical.url.absoluteString + }, + protocolVersion: enrollment.protocolVersion, + enrollment: IdentifierPayload(system: enrollment.enrollment.system.rawValue, value: enrollment.enrollment.value) + ) + } + ) + let bytes = try LedgerEntryCoding.encode(payload) + let digest = Data(SHA256.hash(data: bytes)).base64URLEncodedStringWithoutPadding + self.bytes = bytes + self.digest = digest + self.facts = try Self.decode(bytes, key: LedgerKey.facts(digest)) + } + + /// Rebuilds stored facts through the validating initializers; any fault makes the entry corrupt. + static func decode(_ value: Data, key: String) throws -> ExchangeEventFacts { + let payload = try LedgerEntryCoding.decode(Payload.self, from: value, key: key) + do { + let application = try ApplicationDevice( + name: payload.application.name, + bundleIdentifier: payload.application.bundleIdentifier, + version: payload.application.version, + build: payload.application.build + ) + let host = try HostDevice( + operatingSystemVersion: payload.host.operatingSystemVersion, + name: payload.host.name, + manufacturer: payload.host.manufacturer, + modelNumber: payload.host.modelNumber + ) + let studies = try payload.studies.map { study in + try StudyEnrollment( + study: try identifier(study.study), + protocolURL: try protocolURL(study.protocolURL), + protocolVersion: study.protocolVersion, + enrollment: try identifier(study.enrollment) + ) + } + return ExchangeEventFacts(application: application, host: host, studies: studies) + } catch { + throw ExchangeEventSequencer.LedgerError.corruptEntry(key: key) + } + } + + private static func identifier(_ payload: IdentifierPayload) throws -> BusinessIdentifier { + try BusinessIdentifier(system: IdentifierSystem(payload.system), value: payload.value) + } + + private static func protocolURL(_ text: String?) throws -> FHIRPrimitive { + guard let text else { + return FHIRPrimitive() + } + guard let canonical = text.asFHIRCanonicalPrimitive() else { + throw ExchangeEventSequencer.LedgerError.corruptEntry(key: text) + } + return canonical + } +} diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer+Holds.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer+Holds.swift new file mode 100644 index 000000000..d9b776c3c --- /dev/null +++ b/Sources/GroveFHIRContract/ExchangeEventSequencer+Holds.swift @@ -0,0 +1,83 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +import Foundation + + +/// Which reservations the live calls of this process still hold, and whether any holder released one. +/// +/// The ledger's entries hold no per-call state: a reservation is removed when the last live holder in this +/// process finishes and any holder released it, so overlapping exports of one record never remove each +/// other's reservation, and a call that throws leaves its reservations for the redelivery. Handles include +/// the producer instance, which every ledger mints for itself, so one registry serves every storage. +/// Holds do not span processes; the lock is never held across I/O. +final class HoldRegistry: @unchecked Sendable { // `holds` is guarded by `lock`. + private struct Hold { + var live: Int + var released: Bool + } + + /// The registry every sequencer of this process shares. + static let shared = HoldRegistry() + + private let lock = NSLock() + private var holds: [ExchangeEventReservation.Handle: Hold] = [:] + + /// The number of reservations some live call holds. + var count: Int { + lock.lock() + defer { + lock.unlock() + } + return holds.count + } + + /// Whether no live call holds any reservation. + var isEmpty: Bool { + lock.lock() + defer { + lock.unlock() + } + return holds.isEmpty + } + + /// Takes one hold per handle; called only after the reserving transaction committed. + func acquire(_ handles: some Sequence) { + lock.lock() + defer { + lock.unlock() + } + for handle in handles { + holds[handle, default: Hold(live: 0, released: false)].live += 1 + } + } + + /// Ends one hold per handle and returns the handles whose last live holder just finished and that some + /// holder released: those reservations are no longer needed by anyone in this process. + func end(_ handles: some Sequence, released: Bool) -> [ExchangeEventReservation.Handle] { + lock.lock() + defer { + lock.unlock() + } + var removable: [ExchangeEventReservation.Handle] = [] + for handle in handles { + var hold = holds[handle] ?? Hold(live: 1, released: false) + hold.live -= 1 + hold.released = hold.released || released + if hold.live > 0 { + holds[handle] = hold + } else { + holds[handle] = nil + if hold.released { + removable.append(handle) + } + } + } + return removable + } +} diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer+InMemoryStorage.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer+InMemoryStorage.swift new file mode 100644 index 000000000..0795b62ad --- /dev/null +++ b/Sources/GroveFHIRContract/ExchangeEventSequencer+InMemoryStorage.swift @@ -0,0 +1,85 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +import Foundation + + +extension ExchangeEventSequencer { + /// A ledger that lives in this process only, and the reference implementation of the storage contract. + /// + /// Every launch starts empty and mints a new producer instance, so nothing is ever reused. Use it for + /// tests, previews and single-process tools; share one instance to share one ledger across sequencers. + /// A transaction holds one lock, reads the live map, buffers its writes and applies them only when + /// `body` returns, so a throw commits nothing and a transaction costs what it touches. + public final class InMemoryStorage: Storage, @unchecked Sendable { // `entries` is guarded by `lock`. + /// One transaction: reads see the buffered writes first, then the live map. + private final class Buffered: Transaction { + unowned let storage: InMemoryStorage + /// `nil` removes the key at commit. + var writes: [String: Data?] = [:] + var isOpen = true + + init(storage: InMemoryStorage) { + self.storage = storage + } + + func read(_ key: String) throws -> Data? { + precondition(isOpen, "A ledger transaction is used only inside its body.") + if let write = writes[key] { + return write + } + return storage.entries[key] + } + + func write(_ value: Data, for key: String) throws { + precondition(isOpen, "A ledger transaction is used only inside its body.") + writes[key] = .some(value) + } + + func remove(_ key: String) throws { + precondition(isOpen, "A ledger transaction is used only inside its body.") + writes[key] = .some(nil) + } + + func keys(prefixedBy prefix: String) throws -> [String] { + precondition(isOpen, "A ledger transaction is used only inside its body.") + var keys = Set(storage.entries.keys.filter { $0.hasPrefix(prefix) }) + for (key, value) in writes where key.hasPrefix(prefix) { + if value == nil { + keys.remove(key) + } else { + keys.insert(key) + } + } + return Array(keys) + } + } + + private let lock = NSLock() + private var entries: [String: Data] = [:] + + /// An empty ledger. + public init() {} + + public func transaction(_ body: (any Transaction) throws -> R) throws -> R { + lock.lock() + defer { + lock.unlock() + } + let transaction = Buffered(storage: self) + defer { + transaction.isOpen = false + } + let result = try body(transaction) + for (key, value) in transaction.writes { + entries[key] = value + } + return result + } + } +} diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer+State.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer+State.swift deleted file mode 100644 index 877d0c415..000000000 --- a/Sources/GroveFHIRContract/ExchangeEventSequencer+State.swift +++ /dev/null @@ -1,83 +0,0 @@ -// -// This source file is part of the Grove open-source project -// -// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) -// -// SPDX-License-Identifier: MIT -// - -import Foundation - - -extension ExchangeEventSequencer { - /// The persisted ledger: the producer instance, the next sequence, and the keyed reservations. - /// - /// Stored as JSON under a schema version, so a later layout is recognised rather than misread. - struct State: Codable, Equatable, Sendable { - /// One key's reservation, with every instant as whole milliseconds since 1970-01-01T00:00:00Z. - struct Reservation: Codable, Equatable, Sendable { - let sequence: UInt64 - let instantMilliseconds: Int64 - /// When the reservation was made, for retention; the same instant the reservation hands out. - let reservedAtMilliseconds: Int64 - } - - static let currentSchemaVersion: UInt = 1 - - let schemaVersion: UInt - let producerInstance: UUID - var nextSequence: UInt64 - var reservations: [String: Reservation] - - /// A fresh ledger under a new producer instance, numbering from one. - init() { - self.schemaVersion = Self.currentSchemaVersion - self.producerInstance = UUID() - self.nextSequence = 1 - self.reservations = [:] - } - - /// The stored ledger, or `nil` for an empty storage. - static func decode(_ data: Data?) throws -> State? { - guard let data else { - return nil - } - let state = try JSONDecoder().decode(State.self, from: data) - guard state.schemaVersion == currentSchemaVersion else { - throw StateError.unsupportedSchemaVersion(state.schemaVersion) - } - return state - } - - func encoded() throws -> Data { - try JSONEncoder().encode(self) - } - - /// The key's reservation, or a new one under the next sequence. - mutating func reservation(for key: ExchangeEventKey, instantMilliseconds: Int64) throws -> Reservation { - if let existing = reservations[key.rawValue] { - return existing - } - let (next, overflow) = nextSequence.addingReportingOverflow(1) - guard !overflow else { - throw StateError.sequencesExhausted - } - let reservation = Reservation( - sequence: nextSequence, - instantMilliseconds: instantMilliseconds, - reservedAtMilliseconds: instantMilliseconds - ) - nextSequence = next - reservations[key.rawValue] = reservation - return reservation - } - - /// Forgets every reservation made before `cutoff`; `nil` keeps them all. - mutating func prune(reservedBefore cutoff: Int64?) { - guard let cutoff, reservations.contains(where: { $0.value.reservedAtMilliseconds < cutoff }) else { - return - } - reservations = reservations.filter { $0.value.reservedAtMilliseconds >= cutoff } - } - } -} diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift index 78d93d35c..4480ea402 100644 --- a/Sources/GroveFHIRContract/ExchangeEventSequencer.swift +++ b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift @@ -9,172 +9,184 @@ public import Foundation -/// Hands out exchange-event sequences under one producer instance. +/// The exchange-event ledger of one installation: it hands out event sequences and keeps what each +/// event is rebuilt from until the caller releases it. /// -/// Grove owns the logic; the application supplies durable storage through ``Storage``. The sequencer -/// mints the producer instance on first use and persists it with the counter, so every event an -/// installation emits is numbered under one instance until the storage is reset, after which a new -/// instance starts at one and no sequence is reused under the old one. +/// Grove owns the ledger's logic and its entries; the application supplies durable, transactional +/// storage through ``Storage``. The ledger holds the producer instance and its counter, one reservation +/// per event key an exporter has not yet released, and the facts (application, host, studies) each +/// reservation was minted under. A key that is still reserved, under the same context, returns its +/// reservation unchanged, so an exact redelivery after a crash rebuilds byte-identical output. Nothing +/// is forgotten implicitly; ``forgetReservations(madeBefore:)`` is the explicit maintenance call. /// -/// Exporters reserve a sequence per event key before building the event and release the key once the -/// source has durably acknowledged the event. A key that is still reserved returns its reservation -/// unchanged, so an exact redelivery after a crash reproduces the same event; a reservation that is -/// never released is forgotten after ``Retention/maximumAge``. +/// Every operation is one storage transaction; the sequencer itself holds no lock and no mutable state, +/// so any number of sequencers may share one storage. Calls block for their transaction, so keep them +/// off the main actor. See for the contract a storage must meet. public final class ExchangeEventSequencer: Sendable { - /// Durable, atomic read-modify-write of one opaque blob. + /// Durable, keyed, transactional storage for one ledger. /// - /// A conformance makes the replacement durable before `update` returns and serialises concurrent - /// callers (a lock, an actor hop or a database transaction). The bytes are the sequencer's own; - /// a conformance stores them unchanged and never interprets them. + /// The entries belong to Grove: a storage keeps keys and values byte-exact and never interprets them. + /// A conformance meets the five clauses of : atomicity, durability, + /// serializable isolation, no regression or duplication, and byte-exactness. public protocol Storage: Sendable { - /// Loads the stored blob, lets `body` replace it, persists the replacement and returns `body`'s result. + /// Runs `body` as one transaction and returns its result. /// - /// `nil` is what an empty storage loads; a `body` that throws stores nothing. - func update(_ body: (inout Data?) throws -> R) throws -> R + /// The transaction is valid only inside `body`. Grove never calls `transaction` from inside `body`, + /// and its bodies have no effect outside the transaction, so a storage may discard an attempt and + /// run `body` again. A `body` that throws commits nothing. + func transaction(_ body: (any Transaction) throws -> R) throws -> R } - /// How long a reservation that is never released is kept. - public struct Retention: Hashable, Sendable { - /// Thirty days: long enough for a source to redeliver after a crash, short enough that - /// keys which were never released do not accumulate for the life of an installation. - public static let `default` = Retention(maximumAge: 30 * 24 * 60 * 60) - - /// A reservation made further than this before a later reservation's instant is forgotten - /// at that later reservation; its key then reserves a new sequence. - public let maximumAge: TimeInterval - - /// A retention of `maximumAge` seconds; `.infinity` keeps every reservation until it is released. - public init(maximumAge: TimeInterval) { - precondition(maximumAge > 0, "A reservation is retained for a positive duration.") - self.maximumAge = maximumAge - } - } - - /// Faults in the stored ledger itself; what a ``Storage`` throws propagates unchanged. - public enum StateError: Error, Equatable, Sendable { - /// The ledger was written by a schema this version does not read. - case unsupportedSchemaVersion(UInt) - /// Every sequence under this producer instance has been handed out. - case sequencesExhausted + /// One transaction's view of the ledger: an untyped map from key to value that sees its own writes. + public protocol Transaction { + /// The value stored under `key`, or `nil` when there is none. + func read(_ key: String) throws -> Data? + /// Stores `value` under `key`, replacing any earlier value. + func write(_ value: Data, for key: String) throws + /// Removes `key`; removing an absent key does nothing. + func remove(_ key: String) throws + /// Every key that starts with `prefix`, in no particular order. + /// + /// Grove calls it only from ``ExchangeEventSequencer/reset()`` and + /// ``ExchangeEventSequencer/forgetReservations(madeBefore:)``, never on the export path. + func keys(prefixedBy prefix: String) throws -> [String] } - /// Process-local storage: nothing survives the process, so every launch is a new producer instance. - private final class MemoryStorage: Storage { - private let lock = NSLock() - nonisolated(unsafe) private var data: Data? - - func update(_ body: (inout Data?) throws -> R) throws -> R { - lock.lock() - defer { lock.unlock() } - return try body(&data) - } + /// Faults in the stored entries themselves; errors a ``Storage`` throws propagate unchanged. + /// + /// ``ExchangeEventSequencer/reset()`` is always a safe recovery. + public enum LedgerError: Error, Equatable, Sendable { + /// The entry was written by a later layout; it is refused rather than misread. + case unsupportedEntryVersion(key: String, version: Int) + /// The entry is malformed, out of range, or inconsistent with the ledger, such as a reservation + /// at or above the counter of its own producer instance, or one naming facts the ledger lacks. + case corruptEntry(key: String) } - /// How long a reservation that is never released is kept. - public let retention: Retention - - private let storage: any Storage - /// Serialises this sequencer's own read-modify-write cycles; several sequencers over one storage - /// rely on that storage's serialisation. - private let lock = NSLock() - - /// The installation's producer instance, minted and persisted on first use. - public var producerInstance: UUID { - get throws { - try withState { $0.producerInstance } - } - } + let storage: any Storage + /// Which reservations live calls in this process still hold. + let holds: HoldRegistry /// Creates a sequencer over the application's storage. /// - /// Nothing is read here; the stored ledger is loaded, and any storage error surfaces, on first use. - public init(storage: any Storage, retention: Retention = .default) { + /// Nothing is read here; the ledger is read, and any storage error surfaces, on first use. + public convenience init(storage: any Storage) { + self.init(storage: storage, holds: .shared) + } + + init(storage: any Storage, holds: HoldRegistry) { self.storage = storage - self.retention = retention + self.holds = holds } - /// A sequencer whose ledger lives in this process only, for tests and previews. - public static func inMemory(retention: Retention = .default) -> ExchangeEventSequencer { - ExchangeEventSequencer(storage: MemoryStorage(), retention: retention) + /// A sequencer over a fresh ``InMemoryStorage``, for tests, previews and single-process tools. + public static func inMemory() -> ExchangeEventSequencer { + ExchangeEventSequencer(storage: InMemoryStorage()) } - /// Loads the ledger, creating it when the storage is empty, and stores it back when `body` changed it. - private func withState(_ body: (inout State) throws -> R) throws -> R { - lock.lock() - defer { lock.unlock() } - return try storage.update { data in - let loaded = try State.decode(data) - var state = loaded ?? State() - let result = try body(&state) - if state != loaded { - data = try state.encoded() + /// Forgets every entry in one transaction. + /// + /// The next reservation mints a new producer instance and numbers from one, and a receipt from before + /// the reset releases nothing. Always a safe recovery from ``LedgerError``. + public func reset() throws { + try storage.transaction { transaction in + for key in try transaction.keys(prefixedBy: "") { + try transaction.remove(key) } - return result } } - /// Mutates a ledger that exists; an empty storage is left empty. - private func withExistingState(_ body: (inout State) throws -> Void) throws { - lock.lock() - defer { lock.unlock() } - try storage.update { data in - guard let loaded = try State.decode(data) else { - return + /// Forgets the reservations made before `cutoff`, by their reservation instant, then the facts no + /// remaining reservation references, in one transaction. + /// + /// Grove never calls this itself. It costs time proportional to the ledger. The cutoff and the + /// stored instants are on the caller's clock, so choose a cutoff that tolerates clock skew. A + /// forgotten key that is redelivered becomes a new event, including one a live call still holds. + /// + /// - Returns: The number of reservations forgotten. + @discardableResult + public func forgetReservations(madeBefore cutoff: Date) throws -> Int { + let cutoffMilliseconds = ExchangeInstant.millisecondsSinceEpoch(cutoff) + return try storage.transaction { transaction in + var forgotten = 0 + var referenced: Set = [] + for key in try transaction.keys(prefixedBy: LedgerKey.eventPrefix) { + guard let value = try transaction.read(key) else { + continue + } + let event = try EventEntry(decoding: value, key: key) + if event.instantMilliseconds < cutoffMilliseconds { + try transaction.remove(key) + forgotten += 1 + } else { + referenced.insert(event.facts) + } } - var state = loaded - try body(&state) - if state != loaded { - data = try state.encoded() + for key in try transaction.keys(prefixedBy: LedgerKey.factsPrefix) + where !referenced.contains(String(key.dropFirst(LedgerKey.factsPrefix.count))) { + try transaction.remove(key) } + return forgotten } } } extension ExchangeEventSequencer { - /// One reservation per key, in the keys' order. + /// One reservation per distinct request, durable before this returns. /// - /// A key that is still reserved returns its existing reservation, the same sequence and the same - /// instant, so an exact redelivery reproduces the event. A new key takes the next sequence and - /// `instant` at millisecond precision. Duplicate keys in one call map to one reservation. - /// Reservations older than the retention, measured from `instant`, are forgotten first. Every - /// reservation is durable before this returns, and a sequence is never handed out twice. - package func reserve(_ keys: [ExchangeEventKey], at instant: Date) throws -> [ExchangeEventReservation] { + /// A key whose stored reservation carries the request's fingerprint returns that reservation + /// unchanged: the same producer instance, sequence, instant and facts, and writes nothing. Any other + /// request takes the next sequence at `instant` (millisecond precision) under `facts`, replacing what + /// the key held. New sequences follow the requests' sorted order; a counter that would overflow mints + /// a new producer instance. A sequence is never handed out twice. Each returned reservation is held + /// for the caller until ``finish(_:released:forgetting:)``. + package func reserve( + _ requests: some Collection, + at instant: Date, + facts: ExchangeEventFacts + ) throws -> [ExchangeEventRequest: ExchangeEventReservation] { + let current = try PreparedFacts(facts) + let ordered = Set(requests).sorted { ($0.key.rawValue, $0.fingerprint) < ($1.key.rawValue, $1.fingerprint) } let instantMilliseconds = ExchangeInstant.millisecondsSinceEpoch(instant) - let cutoff = retentionCutoff(before: instantMilliseconds) - return try withState { state in - state.prune(reservedBefore: cutoff) - var reservations: [ExchangeEventReservation] = [] - reservations.reserveCapacity(keys.count) - for key in keys { - let stored = try state.reservation(for: key, instantMilliseconds: instantMilliseconds) - reservations.append(ExchangeEventReservation(stored)) - } - return reservations + let reserved = try storage.transaction { transaction in + var reserving = ReserveTransaction(transaction: transaction, current: current, instantMilliseconds: instantMilliseconds) + return try reserving.reserve(ordered) } + holds.acquire(reserved.values.map(\.handle)) + return reserved } - /// Forgets the reservations of these keys; a key that holds none is ignored. - package func release(_ keys: [ExchangeEventKey]) throws { - try withExistingState { state in - for key in keys { - state.reservations.removeValue(forKey: key.rawValue) - } + /// Ends one hold per handle. + /// + /// `released` says the caller's output is durably handed off. When the last live holder of a + /// reservation in this process finishes and any holder released it, the reservation is removed, but + /// only while the key still holds exactly that reservation. `keys` are forgotten whatever they hold, + /// and only when `released` is true. Opens one transaction when anything is to be removed, none otherwise. + package func finish( + _ held: [ExchangeEventReservation.Handle], + released: Bool, + forgetting keys: [ExchangeEventKey] + ) throws { + let removable = holds.end(held, released: released) + let forgotten = released ? keys : [] + guard !removable.isEmpty || !forgotten.isEmpty else { + return } - } - - /// ``release(_:)`` for a commit action that cannot act on a failure: a reservation that stays - /// behind is harmless, as a redelivery reproduces its event and retention forgets it eventually. - package func releaseIgnoringErrors(_ keys: [ExchangeEventKey]) { - try? release(keys) - } - - /// The instant before which a reservation is forgotten, or `nil` when the retention never expires. - private func retentionCutoff(before instantMilliseconds: Int64) -> Int64? { - guard let maximumAge = Int64(exactly: (retention.maximumAge * 1000).rounded(.up)) else { - return nil + try storage.transaction { transaction in + for handle in removable { + let key = LedgerKey.event(handle.key) + guard let value = try transaction.read(key) else { + continue + } + let stored = try EventEntry(decoding: value, key: key) + if stored.instance == handle.instance && stored.sequence == handle.sequence { + try transaction.remove(key) + } + } + for key in forgotten { + try transaction.remove(LedgerKey.event(key)) + } } - let (cutoff, overflow) = instantMilliseconds.subtractingReportingOverflow(maximumAge) - return overflow ? nil : cutoff } } diff --git a/Sources/GroveFHIRContract/ExchangeGraphAssembler.swift b/Sources/GroveFHIRContract/ExchangeGraphAssembler.swift index 5fa442dda..d23ccd149 100644 --- a/Sources/GroveFHIRContract/ExchangeGraphAssembler.swift +++ b/Sources/GroveFHIRContract/ExchangeGraphAssembler.swift @@ -57,6 +57,11 @@ package struct ExchangeGraphAssembler: Sendable { var resource: ExchangeOutputDraft.Resource } + /// The revision of the graphs this assembler builds. Bump it whenever the bytes it emits can change for + /// equal inputs: it enters every exporter's context fingerprint, so an event reserved under an older + /// revision is never redelivered under the same identifier with different bytes. + package static let outputRevision: UInt = 1 + package let envelope: ExchangeEnvelope package init(envelope: ExchangeEnvelope) { diff --git a/Sources/GroveFHIRContract/ExchangeGraphDraft.swift b/Sources/GroveFHIRContract/ExchangeGraphDraft.swift index 889acf7d2..44a72d13c 100644 --- a/Sources/GroveFHIRContract/ExchangeGraphDraft.swift +++ b/Sources/GroveFHIRContract/ExchangeGraphDraft.swift @@ -34,33 +34,45 @@ package struct ExchangeAdapterContract: Sendable { } -/// Everything about one producer and one source repository that is the same for every event: -/// resolved once, shared by every graph the assembler builds for them. +/// What one graph states about its producer and source repository beside the record itself. +/// +/// The scope half (adapter, identity scope, subject, repository scope) is the same for every event a +/// producer emits; the facts (application, host, studies) are each event's own, frozen at its reservation, +/// and ``with(_:)`` swaps them in per event. package struct ExchangeEnvelope: Sendable { package let adapter: ExchangeAdapterContract package let identityScope: OpaqueIdentityScope package let subject: Subject package let repositoryScope: BusinessIdentifier - package let application: ApplicationDevice - package let host: HostDevice - package let studies: [StudyEnrollment] + package let facts: ExchangeEventFacts + + package var application: ApplicationDevice { facts.application } + package var host: HostDevice { facts.host } + package var studies: [StudyEnrollment] { facts.studies } package init( adapter: ExchangeAdapterContract, identityScope: OpaqueIdentityScope, subject: Subject, repositoryScope: BusinessIdentifier, - application: ApplicationDevice, - host: HostDevice, - studies: [StudyEnrollment] + facts: ExchangeEventFacts ) { self.adapter = adapter self.identityScope = identityScope self.subject = subject self.repositoryScope = repositoryScope - self.application = application - self.host = host - self.studies = studies + self.facts = facts + } + + /// The same scope under one event's facts. + package func with(_ facts: ExchangeEventFacts) -> ExchangeEnvelope { + ExchangeEnvelope( + adapter: adapter, + identityScope: identityScope, + subject: subject, + repositoryScope: repositoryScope, + facts: facts + ) } /// The source-record identity of one native record in this repository. diff --git a/Sources/GroveFHIRContract/ExchangeInstant.swift b/Sources/GroveFHIRContract/ExchangeInstant.swift index 678f8bd94..f442c09ae 100644 --- a/Sources/GroveFHIRContract/ExchangeInstant.swift +++ b/Sources/GroveFHIRContract/ExchangeInstant.swift @@ -67,7 +67,7 @@ package enum ExchangeInstant { /// Milliseconds since 1970-01-01T00:00:00Z, rounded half to even from the instant's own binary64 value. /// /// A non-finite or out-of-range instant saturates; its lexeme then names no FHIR-representable year. - static func millisecondsSinceEpoch(_ date: Date) -> Int64 { + package static func millisecondsSinceEpoch(_ date: Date) -> Int64 { let scaled = (date.timeIntervalSinceReferenceDate * 1000).rounded(.toNearestOrEven) let sinceReference = Int64(exactly: scaled) ?? (scaled < 0 ? .min : .max) let (sum, overflow) = sinceReference.addingReportingOverflow(referenceEpochMilliseconds) diff --git a/Sources/GroveFHIRContract/ExchangeProducer.swift b/Sources/GroveFHIRContract/ExchangeProducer.swift index 71f7477cc..d9972c293 100644 --- a/Sources/GroveFHIRContract/ExchangeProducer.swift +++ b/Sources/GroveFHIRContract/ExchangeProducer.swift @@ -10,7 +10,8 @@ /// /// Immutable; rebuild it when any input changes. The inputs every event shares are checked once /// here, so a deployment fault is reported where the producer is configured rather than inside a -/// conversion, and the sequencer numbers every event the producer emits under one producer instance. +/// conversion. The sequencer numbers every event the producer emits and freezes the application, +/// host and studies each one states, so a redelivery after a rebuild reproduces the same bytes. public final class ExchangeProducer: Sendable { /// A configuration the producer refuses, as every event built under it would be refused. public enum ConfigurationError: Error, Equatable, Sendable { @@ -39,7 +40,7 @@ public final class ExchangeProducer: Sendable { public let host: HostDevice /// The participant's known enrollments, each study once. public let studies: [StudyEnrollment] - /// Where the producer's events take their sequences from. + /// The ledger the producer's events take their sequences and frozen facts from. public let sequencer: ExchangeEventSequencer /// Creates the producer of one installation. diff --git a/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md b/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md new file mode 100644 index 000000000..c69839aa1 --- /dev/null +++ b/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md @@ -0,0 +1,88 @@ +# The exchange ledger and its storage + + + +What a storage behind ``ExchangeEventSequencer`` must guarantee, and how common backends meet it. + +## Overview + +Every exchange event is immutable: a retry resends the same bytes under the same identifier, and a sequence is never handed out for other content. +``ExchangeEventSequencer`` keeps that promise on the device. +It numbers the events of one installation, and until an exporter's receipt is released it keeps, per event key, the producer instance, the sequence, the instant and the facts (application, host, studies) the event states. +An exact redelivery after a crash, an app update or an operating-system update rebuilds byte-identical output from those frozen facts. +When anything that shapes the output but is not frozen has changed (the converter's output revision, the identity scope, the subject, the repository scope or an option), the event takes a new sequence instead. + +Grove owns the ledger's logic and its entries. +Your application supplies only the durable storage, through ``ExchangeEventSequencer/Storage``: a transactional map from string keys to byte values. +``ExchangeEventSequencer/InMemoryStorage`` is the reference implementation, for tests, previews and single-process tools. + +## The storage contract + +A storage meets five clauses. + +| Clause | Guarantee | What breaks without it | +| --- | --- | --- | +| C1 Atomicity | A transaction's writes become visible all together or not at all, including when `body` throws or the commit fails. Reads inside a transaction see its own writes. | The counter advances without the reservation, or the reverse; at worst a sequence is handed out twice. | +| C2 Durability | When `transaction` returns normally, its writes survive process termination, an operating-system crash and power loss for as long as the storage exists. On Apple platforms that takes a device-cache flush (`F_FULLFSYNC`), not only `fsync`. | A graph leaves the device under sequence *n*, then the counter's advance is undone and *n* is reused. | +| C3 Isolation | All transactions on one storage are serializable, across threads, sequencers and processes that open it. | Two concurrent reservations read the same counter. | +| C4 No regression, no duplication | An entry never returns to a value it held earlier, and the entries never become live in a second storage. Losing entries, some or all, is allowed. Restoring an older snapshot (a backup, a commit undone by power loss) and cloning or syncing the storage to another installation are not. | An old counter under a live producer instance, or one counter shared by two installations, reuses sequences. | +| C5 Byte-exactness | Keys compare byte for byte, and values come back byte-identical. | Entries are missed or corrupted. | + +Loss is tolerated because every loss is either harmless or detected. +A lost `producer` entry mints a new producer instance; a lost reservation turns its redelivery into a new event, a duplicate and never a reuse; a lost facts entry raises ``ExchangeEventSequencer/LedgerError/corruptEntry(key:)``. +A reservation found at or above the counter of its own instance reveals a regressed counter and raises the same error. +``ExchangeEventSequencer/reset()`` is always a safe recovery. + +What Grove promises a storage in return: + +- Keys are ASCII from `[A-Za-z0-9_/-]` and at most 64 bytes: `producer`, `event/` and `facts/`. +- Values are UTF-8 JSON, typically under 1 KiB; accept values up to 1 MiB, as facts grow with the number of studies. +- Grove never nests transactions, never lets a transaction escape its body, and its bodies have no effect outside the transaction, so a storage may discard an attempt and run the body again. +- `keys(prefixedBy:)` is called only by ``ExchangeEventSequencer/reset()`` and ``ExchangeEventSequencer/forgetReservations(madeBefore:)``. +- One storage holds one ledger and nothing else. + +## Backends + +| Backend | C1 | C2 | C3 | C4 | C5 | +| --- | --- | --- | --- | --- | --- | +| In memory (``ExchangeEventSequencer/InMemoryStorage``) | Writes are buffered and applied when the body returns. | The storage lives as long as its process; exiting loses every entry, which C4 allows. | One lock per transaction. | It cannot be restored or copied. | Values are stored as given. | +| One file, rewritten atomically | Mutate a copy, write a temporary file in the same directory, rename it over the original. | `F_FULLFSYNC` on the temporary file before the rename, then `fsync` the directory. | A process lock plus `flock` on a sibling lock file that is never replaced. | Exclude the directory from backup; never sync it. | A binary property list `[String: Data]`. | +| Keychain (small or pruned ledgers) | The whole map is one item, replaced in one call. | The keychain commits before the call returns. | A process lock, plus a lock file for app extensions sharing the item. | A this-device-only, non-synchronizable item, guarded by a token also kept in a non-backed-up file; a missing or differing token presents an empty map. | A binary property list `[String: Data]`. | +| Core Data | A private context per transaction and one save, discarded on a throw. | Fully synchronous commits with a device-cache flush. | One process lock; an error merge policy fails a conflicting save, and the body runs again. | Exclude the store from backup; no CloudKit mirroring. | A string key with a uniqueness constraint and a binary value. | +| SQL database | One transaction per call over a relation with a unique key and a binary value. | The engine's fully durable commit, including the device-cache flush. | Serializable isolation, or a transaction that takes the write lock first. | Exclude the database from backup; never restore it from replicas or snapshots. | A key column with binary collation and a binary value column. | + +## Cost and retention + +An export or retraction is one transaction that touches only the entries of its own event keys, the `producer` entry and each distinct facts entry once; a reservation that is reused writes nothing. +Releasing a receipt is at most one more transaction, and none when it reserved nothing. +Backends that store entries individually (in memory, Core Data, SQL) therefore cost what a call touches, whatever the ledger's size. +The single-file and keychain backends rewrite the whole map on every transaction and suit small ledgers, or ledgers you prune. + +Nothing is forgotten implicitly. +A reservation stays until its receipt is released, or until you call ``ExchangeEventSequencer/forgetReservations(madeBefore:)``, which removes the reservations made before a cutoff and the facts no remaining reservation references. +Both the cutoff and the stored instants are on the caller's clock, so choose one that tolerates clock skew. + +## Holds and receipts + +The entries hold no per-call state. +Live calls are tracked in process memory: when the last call in the process that holds an event finishes and any of them released it, the event's reservation is removed, and otherwise it stays for the redelivery. +A release only ever removes the exact reservation its call made, never a successor's or one from before a reset. +Holds do not span processes; when two live processes share one storage, a release in one can remove a reservation the other still holds, and the other's redelivery then becomes a new event, a duplicate and never a reuse. + +## Topics + +### The ledger + +- ``ExchangeEventSequencer`` +- ``ExchangeEventSequencer/Storage`` +- ``ExchangeEventSequencer/Transaction`` +- ``ExchangeEventSequencer/InMemoryStorage`` +- ``ExchangeEventSequencer/LedgerError`` diff --git a/Sources/GroveFHIRContract/GroveFHIRContract.docc/GroveFHIRContract.md b/Sources/GroveFHIRContract/GroveFHIRContract.docc/GroveFHIRContract.md index 168ea90d5..f6fe9bdb8 100644 --- a/Sources/GroveFHIRContract/GroveFHIRContract.docc/GroveFHIRContract.md +++ b/Sources/GroveFHIRContract/GroveFHIRContract.docc/GroveFHIRContract.md @@ -51,7 +51,7 @@ Persist the key id and the epoch beside the key; rotating either changes every s Every export is an exchange event, and every event is immutable. An ``ExchangeEventIdentifier`` is your producer instance UUID plus a monotonic ``EventSequence``. A retry resends the same bytes under the same identifier; a new revision of the record gets a new sequence. -Persist the producer instance once and the next sequence before you emit. +An ``ExchangeProducer``'s ``ExchangeEventSequencer`` mints both and keeps them, with what each event states, in a ledger your app stores; says what that storage must guarantee. ### The repository scope @@ -78,26 +78,24 @@ let identityScope = try OpaqueIdentityScope(systems: systems, keyID: keyID, epoc let application = try ApplicationDevice(bundle: .main) ``` -Per export, reserve the next sequence and create the context, using every default. -`producerInstance` is the UUID persisted with the installation and `nextSequence` the counter you durably advanced first. +Then build the producer over the ledger your app stores, and rebuild it when the participant, the studies or the application change. +`ledgerStorage` conforms to ``ExchangeEventSequencer/Storage``. ```swift -let event = try ExchangeEventIdentifier(system: systems.event, producerInstance: producerInstance, sequence: nextSequence) -let context = ExchangeEventContext( - subject: .logical(participant), - event: event, +let producer = try ExchangeProducer( identityScope: identityScope, - repositoryScope: repositoryScope, - application: application + subject: .logical(participant), + application: application, + sequencer: ExchangeEventSequencer(storage: ledgerStorage) ) ``` -The adapter for your source turns the context and one record into an ``ExchangeGraph``; encode its Bundle and hand it to your uploader. +The exporter for your source mints each event through the producer and turns one record into an ``ExchangeGraph``. +Store and upload its ``ExchangeGraph/json`` verbatim, never a re-encoding of its Bundle, and release the exporter's receipt only once those bytes and your source cursor are durably committed. Before you trust bytes you stored or received, re-validate them. ```swift -let bytes = try JSONEncoder().encode(graph.bundle) -let restored = try ExchangeGraph(kind: .active, jsonData: bytes) +let restored = try ExchangeGraph(validating: storedBytes, kind: .active) precondition(restored.isSemanticallyEqual(to: graph)) ``` @@ -105,12 +103,11 @@ What to persist, and why: | Value | Why | | --- | --- | -| The event sequence, before emitting | A reused sequence under different content is a conflict the receiver cannot resolve. | +| The ledger | It numbers every event and freezes what each one states until the receipt is released; a reused sequence under different content is a conflict the receiver cannot resolve. | | The key id and epoch, beside the key | They select the systems every identity is minted under. | -| The producer instance id | It is half of every event identifier. | -> Important: Never reuse an event sequence for different content, and never change the key or the epoch without deriving new systems. -> Both break the promise that one identifier means one thing. +> Important: Never restore the ledger from a backup or copy it to another installation, and never change the key or the epoch without deriving new systems. +> Each breaks the promise that one identifier means one thing. ## Beyond the minimum @@ -181,6 +178,12 @@ The conformance lane in `Scripts/validate-fhir-conformance.sh` proves an adapter - ``EntryNodeKey`` - ``RepositoryID`` +### The producer and its ledger + +- ``ExchangeProducer`` +- ``ExchangeEventSequencer`` +- + ### The event - ``ExchangeEventContext`` diff --git a/Sources/GroveFHIRContract/LedgerEntryCoding.swift b/Sources/GroveFHIRContract/LedgerEntryCoding.swift new file mode 100644 index 000000000..6916b5c27 --- /dev/null +++ b/Sources/GroveFHIRContract/LedgerEntryCoding.swift @@ -0,0 +1,91 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +import Foundation + + +/// The keys of the ledger's entries: `producer`, `event/` and `facts/`, all ASCII from +/// `[A-Za-z0-9_/-]` and at most 64 bytes. +enum LedgerKey { + static let producer = "producer" + static let eventPrefix = "event/" + static let factsPrefix = "facts/" + + static func event(_ key: ExchangeEventKey) -> String { + eventPrefix + key.rawValue + } + + static func facts(_ digest: String) -> String { + factsPrefix + digest + } +} + + +/// How every ledger value is written and read: JSON with sorted members and unescaped slashes, carrying its +/// layout version under `"v"`. A later version is refused, anything malformed is corrupt; nothing traps. +enum LedgerEntryCoding { + private struct Header: Decodable { + enum CodingKeys: String, CodingKey { + case version = "v" + } + + let version: Int? + } + + static let version = 1 + + static func encode(_ payload: some Encodable) throws -> Data { + let encoder = JSONEncoder() + encoder.outputFormatting = [.sortedKeys, .withoutEscapingSlashes] + return try encoder.encode(payload) + } + + static func decode(_ type: Payload.Type, from value: Data, key: String) throws -> Payload { + let header: Header + do { + header = try JSONDecoder().decode(Header.self, from: value) + } catch { + throw ExchangeEventSequencer.LedgerError.corruptEntry(key: key) + } + guard let version = header.version else { + throw ExchangeEventSequencer.LedgerError.corruptEntry(key: key) + } + guard version <= Self.version else { + throw ExchangeEventSequencer.LedgerError.unsupportedEntryVersion(key: key, version: version) + } + guard version == Self.version else { + throw ExchangeEventSequencer.LedgerError.corruptEntry(key: key) + } + do { + return try JSONDecoder().decode(type, from: value) + } catch { + throw ExchangeEventSequencer.LedgerError.corruptEntry(key: key) + } + } + + /// A canonical positive decimal within `UInt64`, such as a sequence or the next one. + static func positiveInteger(_ text: String) -> UInt64? { + guard CanonicalNonnegativeDecimal.isCanonical(text), text != "0" else { + return nil + } + return UInt64(text) + } + + /// A producer instance: a UUID stating an RFC 4122 version and variant, as every event identifier requires. + static func instance(_ text: String) -> UUID? { + guard let uuid = UUID(uuidString: text), (1...5).contains(uuid.uuid.6 >> 4), uuid.uuid.8 >> 6 == 0b10 else { + return nil + } + return uuid + } + + /// The form of a SHA-256 digest in base64url without padding. + static func isDigest(_ text: String) -> Bool { + text.utf8.count == 43 && text.utf8.allSatisfy { $0.isASCIIAlphaNumeric || $0 == 0x2D || $0 == 0x5F } + } +} diff --git a/Sources/GroveFHIRContract/OpaqueIdentityEncoding.swift b/Sources/GroveFHIRContract/OpaqueIdentityEncoding.swift index 727ca2ace..f6140f2a2 100644 --- a/Sources/GroveFHIRContract/OpaqueIdentityEncoding.swift +++ b/Sources/GroveFHIRContract/OpaqueIdentityEncoding.swift @@ -29,7 +29,8 @@ public enum LengthFramedUTF8 { extension Data { - var base64URLEncodedStringWithoutPadding: String { + /// The bytes in base64url (RFC 4648 §5) without padding. + package var base64URLEncodedStringWithoutPadding: String { base64EncodedString() .replacingOccurrences(of: "+", with: "-") .replacingOccurrences(of: "/", with: "_") diff --git a/Sources/GroveFHIRContract/OpaqueIdentityScope.swift b/Sources/GroveFHIRContract/OpaqueIdentityScope.swift index 457712a2a..c30d30d4e 100644 --- a/Sources/GroveFHIRContract/OpaqueIdentityScope.swift +++ b/Sources/GroveFHIRContract/OpaqueIdentityScope.swift @@ -32,6 +32,22 @@ public struct OpaqueIdentityScope: Sendable, CustomDebugStringConvertible { "OpaqueIdentityScope(keyID: \(keyID), epoch: \(epoch.rawValue))" } + /// Distinguishes the identity scopes one exchange ledger may serve, without revealing the key. + /// + /// HMAC-SHA-256 under the scope's key, base64url without padding, over the length-framed label + /// `org.grovealliance.grove.ledger-context.v0`, the key id, the epoch and every derived system, in + /// their fixed order. A different key, key id, epoch or system yields a different value. + package var ledgerFingerprint: String { + let parts = ["org.grovealliance.grove.ledger-context.v0", keyID, epoch.rawValue] + systems.all.map(\.rawValue) + let framed: Data + do { + framed = try LengthFramedUTF8.encode(parts) + } catch { + preconditionFailure("A validated identity-scope part exceeds the framing limit: \(error)") + } + return Data(HMAC.authenticationCode(for: framed, using: key)).base64URLEncodedStringWithoutPadding + } + /// Creates one identity scope. /// /// Keys shorter than 256 bits are rejected. `keyID` is wire-visible and therefore restricted diff --git a/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/GroveHealthKitFHIR.md b/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/GroveHealthKitFHIR.md index 6516f347d..7548bb050 100644 --- a/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/GroveHealthKitFHIR.md +++ b/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/GroveHealthKitFHIR.md @@ -63,8 +63,8 @@ Use a system your deployment owns and a token you persist once per installation, The conversion Provenance names the application that assembled the graph, so a receiver knows who to trust and which version wrote it. `ApplicationDevice(bundle:)` reads it from your bundle. -> Note: The host defaults to `HostDevice.current()` and the conversion instant to now. -> Pass both explicitly when you replay a persisted event, so the retry rebuilds the same bytes. +> Note: The host defaults to `HostDevice.current()` and the event instant to now. +> The exporter freezes the instant, the application, the host and the studies with each event, so a redelivery before the receipt is released rebuilds the same bytes, even after an update. ## Assemble it @@ -77,38 +77,45 @@ let identityScope = try OpaqueIdentityScope(systems: systems, keyID: keyID, epoc let application = try ApplicationDevice(bundle: .main) ``` -Per export, reserve the next sequence and create the context, using every default. -`producerInstance` is the UUID persisted with the installation, `nextSequence` the counter you durably advanced first, and `installationToken` the token that names this HealthKit store. +Build the producer and the exporter once per configuration, and rebuild both when the participant, the studies or the application change. +`ledgerStorage` is your app's ledger, conforming to `ExchangeEventSequencer.Storage` (`GroveFHIRContract` documents the contract it must meet), and `installationToken` the token that names this HealthKit store. ```swift -let event = try ExchangeEventIdentifier(system: systems.event, producerInstance: producerInstance, sequence: nextSequence) -let context = HealthKitConversionContext(event: ExchangeEventContext( - subject: .logical(participant), - event: event, +let producer = try ExchangeProducer( identityScope: identityScope, - repositoryScope: try BusinessIdentifier(system: "https://study.example.org/fhir/NamingSystem/healthkit-store", value: installationToken), - application: application -)) + subject: .logical(participant), + application: application, + sequencer: ExchangeEventSequencer(storage: ledgerStorage) +) +let exporter = try HealthKitFHIRExporter( + producer: producer, + repositoryScope: try BusinessIdentifier(system: "https://study.example.org/fhir/NamingSystem/healthkit-store", value: installationToken) +) ``` -Convert one sample and hand the Bundle to your uploader. +Export a batch and store each graph's bytes verbatim. +Release the receipt only once the stored graphs and the HealthKit anchor are durably committed; until then an exact redelivery reproduces the same events, byte for byte. ```swift -let conversion = try HealthKitConverter().convert(sample, context: context) -try upload(JSONEncoder().encode(conversion.primary.bundle)) +let receipt = try exporter.export(samples) { export in + if let graph = export.graph { + try stage(graph.json) + } +} +try commitAnchor() +receipt.release() ``` What to persist, and why: | Value | Why | | --- | --- | -| The event sequence, before emitting | A reused sequence under different content is a conflict the receiver cannot resolve. | +| The ledger storage | It numbers every event and freezes what each one states until the receipt is released. Never restore it from a backup or copy it to another installation. | | The key id and epoch, beside the key | They select the systems every identity is minted under. | -| The producer instance id | It is half of every event identifier. | | The installation token | It is the repository scope of every identity this store mints. | -> Important: Never reuse an event sequence for different content, and never change the key or the epoch without deriving new systems. -> Both break the promise that one identifier means one thing. +> Important: Never change the key or the epoch without deriving new systems. +> It breaks the promise that one identifier means one thing. ## Beyond the minimum @@ -203,6 +210,11 @@ The conformance lane in `Scripts/validate-fhir-conformance.sh` proves this adapt - - +### Exporting + +- ``HealthKitFHIRExporter`` +- ``HealthKitFHIRExporter/Receipt`` + ### Conversion - ``HealthKitConverter`` diff --git a/Sources/GroveHealthKitFHIR/HealthKitAssembly+Records.swift b/Sources/GroveHealthKitFHIR/HealthKitAssembly+Records.swift index e7617bf4b..64654a3bc 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitAssembly+Records.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitAssembly+Records.swift @@ -18,9 +18,17 @@ import ModelsR4 @available(iOS 18, macOS 15, watchOS 11, *) extension HealthKitAssembly { + /// The requests of an ECG's correlated symptoms. + enum SymptomRequests { + /// One request per symptom, in the record's order: the context API's shape. + case positional([Request]) + /// Each symptom's request under its sample's UUID: the exporter's shape, paired by event key. + case keyed([UUID: Request]) + } + /// Converts an already-fetched ECG and every correlated symptom as independently exchangeable - /// source events: one request per symptom, in the record's order. - func convertECG(_ record: HealthKitECGRecord, request: Request, symptomRequests: [Request]) throws -> HealthKitConversionSet { + /// source events, each symptom under its own request. + func convertECG(_ record: HealthKitECGRecord, request: Request, symptomRequests: SymptomRequests) throws -> HealthKitConversionSet { let source = try HealthKitConverter.ecgSourceEvidence(record.electrocardiogram) return try convertECG( record.electrocardiogram, @@ -37,7 +45,7 @@ extension HealthKitAssembly { evidence: HealthKitECGEvidence, symptoms: [HKCategorySample], request: Request, - symptomRequests: [Request] + symptomRequests: SymptomRequests ) throws -> HealthKitConversionSet { let companions = try symptomConversions(symptoms, source: evidence.source, symptomRequests: symptomRequests) let input = HealthKitECGObservationInput( @@ -69,22 +77,29 @@ extension HealthKitAssembly { private func symptomConversions( _ correlatedSymptoms: [HKCategorySample], source: HealthKitECGSourceEvidence, - symptomRequests: [Request] + symptomRequests: SymptomRequests ) throws -> [HealthKitConversion] { - guard symptomRequests.count == correlatedSymptoms.count else { - throw HealthKitConversionError.ecgEvidence(.symptomContextCountMismatch( - symptoms: correlatedSymptoms.count, - contexts: symptomRequests.count - )) + let requestsBySample: [UUID: Request] + switch symptomRequests { + case .positional(let requests): + guard requests.count == correlatedSymptoms.count else { + throw HealthKitConversionError.ecgEvidence(.symptomContextCountMismatch( + symptoms: correlatedSymptoms.count, + contexts: requests.count + )) + } + requestsBySample = Dictionary(zip(correlatedSymptoms.map(\.uuid), requests), uniquingKeysWith: { first, _ in first }) + case .keyed(let requests): + requestsBySample = requests } - let requestsBySample = Dictionary( - zip(correlatedSymptoms.map(\.uuid), symptomRequests), - uniquingKeysWith: { first, _ in first } - ) + // Validation comes first, so an unsupported or duplicated symptom is refused as such. let symptoms = try HealthKitConverter.validatedSymptomSamples(correlatedSymptoms, status: source.symptomsStatus) return try symptoms.map { symptom in guard let request = requestsBySample[symptom.uuid] else { - throw HealthKitConversionError.ecgEvidence(.duplicateSymptomSource(symptom.uuid)) + throw HealthKitConversionError.ecgEvidence(.symptomContextCountMismatch( + symptoms: correlatedSymptoms.count, + contexts: requestsBySample.count + )) } return try convert(symptom, request: request).primary } diff --git a/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift b/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift index 73a702695..e5c1a1caf 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift @@ -20,10 +20,13 @@ import ModelsR4 /// its writer and recording device, and hands the draft to the shared ``ExchangeGraphAssembler``. @available(iOS 18, macOS 15, watchOS 11, *) struct HealthKitAssembly: Sendable { - /// What one record's conversion needs beyond the envelope: its event, and the policies in force. + /// What one record's conversion needs beyond the envelope's scope: its event, the facts frozen with it, + /// and the policies in force. struct Request: Sendable { let event: ExchangeEventIdentifier let instant: Date + /// The application, host and studies the event states, as its reservation froze them. + let facts: ExchangeEventFacts let converterRole: ConverterRole let repositoryIDs: [ExchangeGraphNode: RepositoryID] let options: HealthKitConversionOptions @@ -31,12 +34,14 @@ struct HealthKitAssembly: Sendable { init( event: ExchangeEventIdentifier, instant: Date, + facts: ExchangeEventFacts, converterRole: ConverterRole = .assembler, repositoryIDs: [ExchangeGraphNode: RepositoryID] = [:], options: HealthKitConversionOptions = .default ) { self.event = event self.instant = instant + self.facts = facts self.converterRole = converterRole self.repositoryIDs = repositoryIDs self.options = options @@ -46,6 +51,7 @@ struct HealthKitAssembly: Sendable { self.init( event: context.event.event, instant: context.event.conversionInstant, + facts: ExchangeEventFacts(context.event), converterRole: context.event.converterRole, repositoryIDs: context.event.repositoryIDs, options: context.options @@ -53,6 +59,11 @@ struct HealthKitAssembly: Sendable { } } + /// The revision of the graphs this adapter's assembly builds. Bump it whenever the bytes it emits can + /// change for equal inputs: it enters every exporter's context fingerprint, so an event reserved under an + /// older revision is never redelivered under the same identifier with different bytes. + static let outputRevision: UInt = 1 + static let adapter = ExchangeAdapterContract( adapterID: "healthkit", provenanceProfile: HealthKitContract.conversionProvenanceProfile, @@ -69,12 +80,11 @@ struct HealthKitAssembly: Sendable { ) } - let assembler: ExchangeGraphAssembler - - var envelope: ExchangeEnvelope { assembler.envelope } + /// The producer's scope; each graph takes its own request's facts. + let envelope: ExchangeEnvelope init(envelope: ExchangeEnvelope) { - self.assembler = ExchangeGraphAssembler(envelope: envelope) + self.envelope = envelope } init(context: ExchangeEventContext) { @@ -83,9 +93,7 @@ struct HealthKitAssembly: Sendable { identityScope: context.identityScope, subject: context.subject, repositoryScope: context.repositoryScope, - application: context.application, - host: context.host, - studies: context.studies + facts: ExchangeEventFacts(context) )) } @@ -146,7 +154,7 @@ struct HealthKitAssembly: Sendable { converterRole: request.converterRole, repositoryIDs: request.repositoryIDs ) - let assembled = try assembler.assemble(draft) + let assembled = try ExchangeGraphAssembler(envelope: envelope.with(request.facts)).assemble(draft) return HealthKitConversion( source: source, identifiers: assembled.identifiers, @@ -189,21 +197,29 @@ extension HealthKitAssembly { return version == build && revision.source.bundleIdentifier == application.bundleIdentifier } - /// The event context a retraction or a bundled study context is minted from. + /// The event context a retraction or a bundled study context is minted from, under the request's facts. func eventContext(for request: Request) -> ExchangeEventContext { ExchangeEventContext( subject: envelope.subject, event: request.event, identityScope: envelope.identityScope, repositoryScope: envelope.repositoryScope, - application: envelope.application, - host: envelope.host, + application: request.facts.application, + host: request.facts.host, conversionInstant: request.instant, converterRole: request.converterRole, - studies: envelope.studies, + studies: request.facts.studies, repositoryIDs: request.repositoryIDs ) } } + +extension ExchangeEventFacts { + /// The facts an explicit event context states. + init(_ context: ExchangeEventContext) { + self.init(application: context.application, host: context.host, studies: context.studies) + } +} + #endif diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+ECG.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+ECG.swift index 482d3b0ea..a657e86f5 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+ECG.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter+ECG.swift @@ -38,7 +38,7 @@ extension HealthKitConverter { return try HealthKitAssembly(context: context.event).convertECG( record, request: .init(context: context), - symptomRequests: symptomContexts.map { .init(context: $0) } + symptomRequests: .positional(symptomContexts.map { .init(context: $0) }) ) } catch { throw HealthKitConversionError(conversionFailure: error, source: .electrocardiogram) diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift new file mode 100644 index 000000000..e9aaa7869 --- /dev/null +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift @@ -0,0 +1,205 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import CryptoKit +import Foundation +import GroveFHIRContract +import HealthKit +import ModelsR4 + + +/// A configuration value as the context fingerprint states it: a tag naming the case, then its values. +/// +/// Each conformance derives its parts by an exhaustive `switch` without a `default`, so a new case or +/// associated value cannot enter the exporter without entering the fingerprint. A case's tag fixes how many +/// parts follow it, so the length-framed sequence stays unambiguous. +protocol ExchangeContextFingerprinted { + var fingerprintParts: [String] { get } +} + + +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitFHIRExporter { + /// The output revisions a context fingerprint states. + struct OutputRevisions: Hashable, Sendable { + /// The revisions this build emits. + static let current = OutputRevisions(assembler: ExchangeGraphAssembler.outputRevision, healthKit: HealthKitAssembly.outputRevision) + + let assembler: UInt + let healthKit: UInt + } + + /// Everything that shapes this exporter's graphs but is not frozen with an event: the output revisions, + /// the identity scope, the subject, the repository scope and every option. + /// + /// A request's fingerprint is the SHA-256, base64url without padding, of the length-framed call parts + /// followed by the record's own parts. A stored reservation is reused only under an equal fingerprint, so + /// a Grove update that changes output, any option change, or another participant over the same ledger + /// never reuses an event identifier for other bytes. A custom ``RecordingDevicePolicy`` resolver enters + /// by its presence only; its behaviour is not fingerprinted. + struct ExportContext: Sendable { + /// The parts every request of this exporter starts with, in order. + let callParts: [String] + private let framedCallParts: Data + + init(producer: ExchangeProducer, repositoryScope: BusinessIdentifier, options: Options, revisions: OutputRevisions) { + var parts = [ + "grove-healthkit-context-v0", + "outputRevisions", String(revisions.assembler), String(revisions.healthKit), + "identityScope", producer.identityScope.ledgerFingerprint, + "subject" + ] + parts += producer.subject.fingerprintParts + parts += ["repositoryScope", repositoryScope.system.rawValue, repositoryScope.value] + for option in options.fingerprintParts { + parts += [option.property] + option.parts + } + self.callParts = parts + self.framedCallParts = Self.framed(parts) + } + + private static func framed(_ parts: [String]) -> Data { + do { + return try LengthFramedUTF8.encode(parts) + } catch { + preconditionFailure("A context fingerprint part exceeds the framing limit: \(error)") + } + } + + /// The request of one event key with the record parts the key does not version. + func request(for key: ExchangeEventKey, recordParts: [String] = []) -> ExchangeEventRequest { + let digest = SHA256.hash(data: framedCallParts + Self.framed(recordParts)) + return ExchangeEventRequest(key: key, fingerprint: Data(digest).base64URLEncodedStringWithoutPadding) + } + } +} + + +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitFHIRExporter.Options { + /// Every stored option and its fingerprint parts, in declaration order. The completeness test compares + /// the property names with the stored properties ``HealthKitFHIRExporter/Options`` declares. + var fingerprintParts: [(property: String, parts: [String])] { + let options: [(String, any ExchangeContextFingerprinted)] = [ + ("writer", writer), + ("recordingDevice", recordingDevice), + ("role", role), + ("nativeIdentifier", nativeIdentifier), + ("udi", udi), + ("route", route), + ("legacyBundleID", legacyBundleID) + ] + return options.map { (property: $0.0, parts: $0.1.fingerprintParts) } + } +} + + +/// An optional value's parts: a presence tag, then the value. +private func optionalParts(_ value: String?) -> [String] { + value.map { ["some", $0] } ?? ["none"] +} + + +extension Subject: ExchangeContextFingerprinted { + var fingerprintParts: [String] { + switch self { + case .logical(let identifier): + return ["logical", identifier.system.rawValue, identifier.value] + case let .bundled(identifier, patient): + let encoder = JSONEncoder() + encoder.outputFormatting = [.sortedKeys, .withoutEscapingSlashes] + // A Patient that cannot be encoded cannot be emitted either; a unique part keeps any reservation unreused. + let patientJSON = (try? encoder.encode(patient)).map { String(decoding: $0, as: UTF8.self) } ?? "unencodable:\(UUID())" + return ["bundled", identifier.system.rawValue, identifier.value, patientJSON] + } + } +} + + +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitFHIRExporter.WriterPolicy: ExchangeContextFingerprinted { + var fingerprintParts: [String] { + switch self { + case .automatic: ["automatic"] + case .application: ["application"] + case .device: ["device"] + case .omit: ["omit"] + } + } +} + + +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitFHIRExporter.RecordingDevicePolicy: ExchangeContextFingerprinted { + var fingerprintParts: [String] { + switch self { + case .localIdentifier: ["localIdentifier"] + case .omit: ["omit"] + case .custom: ["custom"] + } + } +} + + +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitFHIRExporter.RolePolicy: ExchangeContextFingerprinted { + var fingerprintParts: [String] { + switch self { + case .assembler: + ["assembler"] + case .gatewayForOwnWrites: + ["gatewayForOwnWrites"] + case .gateway: + ["gateway"] + case .gatewayApplication(let application): + ["gatewayApplication", application.name, application.bundleIdentifier, application.version] + optionalParts(application.build) + } + } +} + + +extension GovernedSourceIdentifierDisclosurePolicy: ExchangeContextFingerprinted { + var fingerprintParts: [String] { + switch self { + case .omit: + return ["omit"] + case let .authorized(system, type): + // The type changes `Identifier.type` on every disclosed identifier. + let typeParts = type.map { ["typed", $0.system.rawValue, $0.code] + optionalParts($0.display) } ?? ["untyped"] + return ["authorized", system.rawValue] + typeParts + } + } +} + + +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitFHIRExporter.Disclosure: ExchangeContextFingerprinted { + var fingerprintParts: [String] { + switch self { + case .omit: ["omit"] + case .authorized: ["authorized"] + } + } +} + + +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitFHIRExporter.LegacyBundleID: ExchangeContextFingerprinted { + /// Deprecated only because it names the deprecated case; the fingerprint reads it through the protocol. + @available(*, deprecated, message: "Names the transitional legacy case; read it through ExchangeContextFingerprinted.") + var fingerprintParts: [String] { + switch self { + case .none: ["none"] + case .healthKitUUID: ["healthKitUUID"] + } + } +} + +#endif diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift index a12bf6d87..b40bb90e4 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift @@ -71,7 +71,7 @@ extension HealthKitFHIRExporter { } public enum Outcome: Sendable { - /// The validated graph; store or upload ``ExchangeGraph/json`` verbatim. + /// The validated graph; store or upload `ExchangeGraph.json` verbatim. case graph(ExchangeGraph) /// The record was refused; nothing was emitted and the export continued. Refusals are /// deterministic, so an exact redelivery refuses identically. @@ -91,17 +91,59 @@ extension HealthKitFHIRExporter { } } - /// What an export call reserved. Call ``release()`` once every produced graph is durably stored AND - /// the source cursor (HealthKit anchor, bulk-export checkpoint) is committed; until then an exact - /// redelivery of the same records reproduces the same events. - public struct Receipt: Sendable { - let keys: [ExchangeEventKey] - let sequencer: ExchangeEventSequencer + /// What an export or retraction reserved. + /// + /// Call ``release()`` once every produced graph is durably stored AND the source cursor (HealthKit anchor, + /// bulk-export checkpoint) is committed. Until then an exact redelivery of the same records reproduces the + /// same events, byte for byte. Releasing is idempotent, also across copies of this reference, and makes + /// one ledger transaction at most: none when nothing was reserved, or while another call in this process + /// still holds the same events. + /// + /// A receipt dropped unreleased (the call threw, or its commit action was discarded) leaves its + /// reservations for the redelivery. When another call in this process released the same event, the last + /// one to finish removes it, which may run one ledger transaction on the thread that drops the receipt. A + /// release that fails keeps the reservations; a later release of the same events, a later exact export, + /// or `ExchangeEventSequencer.reset()` removes them. + public final class Receipt: @unchecked Sendable { // `isFinished` is guarded by `lock`. + private let sequencer: ExchangeEventSequencer + private let held: [ExchangeEventReservation.Handle] + private let forgetting: [ExchangeEventKey] + private let lock = NSLock() + private var isFinished = false - /// Forgets the reservations. Idempotent; storage failures are swallowed because a late release only - /// means a later redelivery becomes a new event. + init(sequencer: ExchangeEventSequencer, held: [ExchangeEventReservation.Handle], forgetting: [ExchangeEventKey]) { + self.sequencer = sequencer + self.held = held + self.forgetting = forgetting + } + + /// Ends this call's hold on its reservations, so the next export of the same records is a new event. + /// + /// Only the first call counts. Storage failures are swallowed: a reservation that stays behind only + /// makes a later exact export reproduce the same event. public func release() { - sequencer.releaseIgnoringErrors(keys) + guard claim() else { + return + } + try? sequencer.finish(held, released: true, forgetting: forgetting) + } + + private func claim() -> Bool { + lock.lock() + defer { + lock.unlock() + } + guard !isFinished else { + return false + } + isFinished = true + return true + } + + deinit { + if !isFinished, !held.isEmpty { + try? sequencer.finish(held, released: false, forgetting: []) + } } } } diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift index 79b326b5e..3d250f5c2 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift @@ -18,30 +18,42 @@ extension HealthKitFHIRExporter { /// Retracts deleted records in input order, one retraction event per deletion that names outputs this /// exporter can have emitted; every other deletion is reported as ``Export/Outcome/nothingToRetract``. /// Targets are recomputed from the catalog, so nothing from the original export needs to be kept. - /// Errors from the sequencer's storage and from `receive` end the call. + /// + /// Every retraction event is reserved in one ledger transaction. Two deletions of one record with + /// different bounds are two events. Releasing the receipt also forgets each deleted record's active + /// reservation, which no export will release once the record is gone. Errors from the sequencer's + /// storage and from `receive` end the call. public func retract( _ deletions: some Collection, at instant: Date = .now, receive: (Export) throws -> Void ) throws -> Receipt { - let keys = deletions.filter(isRetractable).map(ExchangeEventKey.retraction) - var reservations = (keys.isEmpty ? [] : try producer.sequencer.reserve(keys, at: instant)).makeIterator() - let producerInstance = keys.isEmpty ? UUID() : try producer.sequencer.producerInstance - for deletion in deletions { - guard isRetractable(deletion), let reservation = reservations.next() else { + let requests = deletions.map { deletion in + isRetractable(deletion) ? context.request(for: .retraction(deletion), recordParts: deletion.occurrenceParts) : nil + } + let unique = Set(requests.compactMap(\.self)) + let reserved = unique.isEmpty ? [:] : try producer.sequencer.reserve(unique, at: instant, facts: producer.facts) + // Created before any delivery: when a delivery throws, the receipt is dropped and its holds lapse. + let receipt = Receipt( + sequencer: producer.sequencer, + held: reserved.values.map(\.handle), + forgetting: deletions.map { ExchangeEventKey.active(type: $0.sourceType, uuid: $0.uuid) } + ) + for (deletion, request) in zip(deletions, requests) { + guard let request, let reservation = reserved[request] else { try receive(Export(source: deletion.source, outcome: .nothingToRetract, warnings: [])) continue } + // A refusal keeps its reservation held until the receipt is released, never mid-call. let outcome: Export.Outcome do { - outcome = .graph(try retraction(of: deletion, reservation: reservation, producerInstance: producerInstance)) + outcome = .graph(try retraction(of: deletion, reservation: reservation)) } catch { - producer.sequencer.releaseIgnoringErrors([ExchangeEventKey.retraction(deletion)]) outcome = .refused(HealthKitConversionError(conversionFailure: error, source: deletion.sourceType)) } try receive(Export(source: deletion.source, outcome: outcome, warnings: [])) } - return Receipt(keys: keys, sequencer: producer.sequencer) + return receipt } /// Whether a deletion names outputs this exporter can have emitted. A type without outputs never emitted any, @@ -54,28 +66,20 @@ extension HealthKitFHIRExporter { return deletion.sourceType != .workoutRoute || options.route == .authorized } - private func retraction( - of deletion: Deletion, - reservation: ExchangeEventReservation, - producerInstance: UUID - ) throws -> ExchangeGraph { + private func retraction(of deletion: Deletion, reservation: ExchangeEventReservation) throws -> ExchangeGraph { let request = HealthKitAssembly.Request( event: try ExchangeEventIdentifier( system: producer.identityScope.systems.event, - producerInstance: producerInstance, + producerInstance: reservation.producerInstance, sequence: reservation.sequence ), instant: reservation.instant, + facts: reservation.facts, repositoryIDs: try legacyRepositoryIDs(for: deletion.uuid), options: HealthKitConversionOptions(nativeIdentifierDisclosure: options.nativeIdentifier) ) let record = HealthKitSourceRecord(uuid: deletion.uuid, type: deletion.sourceType) - // A backwards clock adjustment can put the earlier query after the detection; keep the known - // upper bound rather than stating an invalid period. - let occurred = RetractionOccurrence.period( - start: deletion.deletedAfter.flatMap { $0 <= deletion.detectedAt ? $0 : nil }, - end: deletion.detectedAt - ) + let occurred = RetractionOccurrence.period(start: deletion.clampedDeletedAfter, end: deletion.detectedAt) return try assembly.retraction(of: record, request: request, occurred: occurred).graph } } @@ -86,6 +90,20 @@ extension HealthKitFHIRExporter.Deletion { var source: HealthKitFHIRExporter.Export.Source { HealthKitFHIRExporter.Export.Source(uuid: uuid, typeIdentifier: sourceType.rawValue) } + + /// The lower bound the retraction states. A backwards clock adjustment can put the earlier query after + /// the detection; the known upper bound is kept rather than an invalid period stated. + var clampedDeletedAfter: Date? { + deletedAfter.flatMap { $0 <= detectedAt ? $0 : nil } + } + + /// What the retraction key does not version but the graph states: the bounds, in milliseconds. + var occurrenceParts: [String] { + [ + clampedDeletedAfter.map { String(ExchangeInstant.millisecondsSinceEpoch($0)) } ?? "", + String(ExchangeInstant.millisecondsSinceEpoch(detectedAt)) + ] + } } diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift index 29c837a5a..bb4179824 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift @@ -15,11 +15,12 @@ public import HealthKit /// Turns HealthKit samples into exchange graphs for one deployment, participant and installation. /// -/// Configure it once and keep it for as long as its ``ExchangeProducer`` is valid; it is safe to share -/// across tasks. Every export mints the events itself through the producer's sequencer, so an exact -/// redelivery before ``Receipt/release()`` reproduces the same events, and a sample that cannot be -/// converted is reported as a refusal instead of ending the call. The exporter never queries HealthKit: -/// companion data such as ECG voltages arrives through ``Record``. +/// Configure it once and keep it for as long as its `ExchangeProducer` is valid; it is safe to share +/// across tasks. Every export mints the events itself through the producer's sequencer, in one ledger +/// transaction per call, so an exact redelivery before ``Receipt/release()`` reproduces the same events +/// byte for byte, even when the application, the host or the studies changed in between. A sample that +/// cannot be converted is reported as a refusal instead of ending the call. The exporter never queries +/// HealthKit: companion data such as ECG voltages arrives through ``Record``. @available(iOS 18, macOS 15, watchOS 11, *) public final class HealthKitFHIRExporter: Sendable { /// Why an exporter could not be configured. @@ -33,11 +34,23 @@ public final class HealthKitFHIRExporter: Sendable { public let repositoryScope: BusinessIdentifier public let options: Options let assembly: HealthKitAssembly + /// What shapes every graph beside the frozen facts; it fingerprints each request. + let context: ExportContext - public init( + public convenience init( producer: ExchangeProducer, repositoryScope: BusinessIdentifier, options: Options = Options() + ) throws(ConfigurationError) { + try self.init(producer: producer, repositoryScope: repositoryScope, options: options, outputRevisions: .current) + } + + /// An exporter that fingerprints its requests under `outputRevisions`; tests vary them. + init( + producer: ExchangeProducer, + repositoryScope: BusinessIdentifier, + options: Options, + outputRevisions: OutputRevisions ) throws(ConfigurationError) { if case .authorized(let system, _) = options.nativeIdentifier, producer.identityScope.systems.all.contains(system) { @@ -51,15 +64,14 @@ public final class HealthKitFHIRExporter: Sendable { identityScope: producer.identityScope, subject: producer.subject, repositoryScope: repositoryScope, - application: producer.application, - host: producer.host, - studies: producer.studies + facts: producer.facts )) + self.context = ExportContext(producer: producer, repositoryScope: repositoryScope, options: options, revisions: outputRevisions) } /// Converts samples in input order, calling `receive` once per produced graph or refusal as soon as /// it is ready. Only the sequencer's storage and `receive` itself can end the call early; their - /// errors are rethrown unchanged. + /// errors are rethrown unchanged, and the reservations stay for the redelivery. public func export( _ samples: Samples, at instant: Date = .now, @@ -74,59 +86,111 @@ public final class HealthKitFHIRExporter: Sendable { at instant: Date = .now, receive: (Export) throws -> Void ) throws -> Receipt { - let plans = records.map(Plan.init) - let keys = plans.flatMap(\.keys) - // Nothing reserved means the ledger is never touched; refusals alone need no producer instance. - let reservations = keys.isEmpty ? [] : try producer.sequencer.reserve(keys, at: instant) - let producerInstance = keys.isEmpty ? UUID() : try producer.sequencer.producerInstance - var offset = 0 + try export(inputs: records.map(Input.record), at: instant, receive: receive) + } + + /// One reserve transaction for every event the inputs need, then each input's delivery in order. + func export(inputs: [Input], at instant: Date, receive: (Export) throws -> Void) throws -> Receipt { + let plans = inputs.map { Plan($0, context: context) } + let requests = Set(plans.flatMap(\.requests)) + // Nothing reserved means the ledger is never touched; refusals alone need no event. + let reserved = requests.isEmpty ? [:] : try producer.sequencer.reserve(requests, at: instant, facts: producer.facts) + // Created before any delivery: when a delivery throws, the receipt is dropped and its holds lapse. + let receipt = Receipt(sequencer: producer.sequencer, held: reserved.values.map(\.handle), forgetting: []) for plan in plans { - let reserved = Array(reservations[offset..<(offset + plan.keys.count)]) - offset += plan.keys.count try autoreleasepool { - try deliver(plan, reservations: reserved, producerInstance: producerInstance, receive: receive) + try deliver(plan, reserved: reserved, receive: receive) } } - return Receipt(keys: keys, sequencer: producer.sequencer) + return receipt } } @available(iOS 18, macOS 15, watchOS 11, *) extension HealthKitFHIRExporter { - /// One record and the event keys it needs: one for itself, one per ECG symptom. + /// What one delivery converts: a record, or, below the public API, an ECG whose evidence is already validated. + enum Input { + case record(Record) + /// An ECG with prebuilt evidence: the seam tests use, as `HKElectrocardiogram.VoltageMeasurement` + /// cannot be constructed with values outside HealthKit. + case electrocardiogramEvidence(HKSample, evidence: HealthKitECGEvidence, symptoms: [HKCategorySample]) + + var sample: HKSample { + switch self { + case .record(let record): record.sample + case .electrocardiogramEvidence(let ecg, _, _): ecg + } + } + + /// The correlated symptoms, each its own event. + var symptoms: [HKCategorySample] { + switch self { + case .record(.electrocardiogram(_, _, let symptoms)), .electrocardiogramEvidence(_, _, let symptoms): symptoms + case .record: [] + } + } + + /// What the record's event key does not version but its graph embeds: an ECG references its + /// symptoms' output identifiers, so their set enters the fingerprint. + var recordParts: [String] { + switch self { + case .record(.electrocardiogram), .electrocardiogramEvidence: + symptoms.map { $0.uuid.uuidString.lowercased() }.sorted() + case .record: + [] + } + } + } + + /// One input and the requests it needs: one for its record, one per registered ECG symptom. struct Plan { - let record: Record - let keys: [ExchangeEventKey] - let refusal: HealthKitConversionError? + let input: Input + let primary: ExchangeEventRequest? + /// One entry per correlated symptom, in the record's order; `nil` for a symptom of an unregistered type. + let symptoms: [ExchangeEventRequest?] + + var requests: [ExchangeEventRequest] { + [primary].compactMap(\.self) + symptoms.compactMap(\.self) + } var source: Export.Source { - Export.Source(uuid: record.sample.uuid, typeIdentifier: record.sample.sampleType.identifier) + Export.Source(uuid: input.sample.uuid, typeIdentifier: input.sample.sampleType.identifier) + } + + init(_ input: Input, context: ExportContext) { + let primary = ExchangeEventKey.active(input.sample).map { context.request(for: $0, recordParts: input.recordParts) } + self.input = input + self.primary = primary + // A record that is refused outright reserves nothing for its symptoms either. + self.symptoms = primary == nil ? [] : input.symptoms.map { symptom in + ExchangeEventKey.active(symptom).map { context.request(for: $0) } + } } } private func deliver( _ plan: Plan, - reservations: [ExchangeEventReservation], - producerInstance: UUID, + reserved: [ExchangeEventRequest: ExchangeEventReservation], receive: (Export) throws -> Void ) throws { - if let refusal = plan.refusal { + guard let primary = plan.primary else { + let refusal = HealthKitConversionError.unregisteredSourceType(plan.input.sample.sampleType.identifier) try receive(Export(source: plan.source, outcome: .refused(refusal), warnings: [])) return } + // A refusal keeps its reservations held: they are released with the receipt, never mid-call, so a + // standalone export of the same record in this call keeps its event. let set: HealthKitConversionSet? do { - set = try convert(plan.record, reservations: reservations, producerInstance: producerInstance) + set = try convert(plan, primary: reservation(for: primary, in: reserved), reserved: reserved) } catch { let failure = HealthKitConversionError(conversionFailure: error, source: plan.source.sourceType) - producer.sequencer.releaseIgnoringErrors(plan.keys) try receive(Export(source: plan.source, outcome: .refused(failure), warnings: [])) return } guard let set else { // A policy chose to emit nothing (an unauthorized route); that is not a refusal and never warns. - producer.sequencer.releaseIgnoringErrors(plan.keys) return } for conversion in set.all { @@ -138,26 +202,56 @@ extension HealthKitFHIRExporter { } } + private func reservation( + for request: ExchangeEventRequest, + in reserved: [ExchangeEventRequest: ExchangeEventReservation] + ) -> ExchangeEventReservation { + guard let reservation = reserved[request] else { + preconditionFailure("Every planned request is reserved in the same call.") + } + return reservation + } + private func convert( - _ record: Record, - reservations: [ExchangeEventReservation], - producerInstance: UUID + _ plan: Plan, + primary: ExchangeEventReservation, + reserved: [ExchangeEventRequest: ExchangeEventReservation] ) throws -> HealthKitConversionSet? { - let request = try request(for: record.sample, reservation: reservations[0], producerInstance: producerInstance) - switch record { - case .sample(let sample): + let request = try request(for: plan.input.sample, reservation: primary) + switch plan.input { + case .record(.sample(let sample)): return try assembly.convert(sample, request: request) - case let .electrocardiogram(ecg, voltages, symptoms): - let symptomRequests = try zip(symptoms, reservations.dropFirst()).map { symptom, reservation in - try self.request(for: symptom, reservation: reservation, producerInstance: producerInstance) - } + case let .record(.electrocardiogram(ecg, voltages, symptoms)): let ecgRecord = HealthKitECGRecord(electrocardiogram: ecg, voltageMeasurements: voltages, correlatedSymptoms: symptoms) - return try assembly.convertECG(ecgRecord, request: request, symptomRequests: symptomRequests) - case let .heartbeatSeries(series, beats): + return try assembly.convertECG(ecgRecord, request: request, symptomRequests: symptomRequests(plan, reserved: reserved)) + case let .record(.heartbeatSeries(series, beats)): return try assembly.convertHeartbeatSeries(HealthKitHeartbeatSeriesRecord(series: series, heartbeats: beats), request: request) - case let .workoutRoute(route, locations): + case let .record(.workoutRoute(route, locations)): return try assembly.convertWorkoutRoute(HealthKitWorkoutRouteRecord(route: route, locations: locations), request: request) + case let .electrocardiogramEvidence(ecg, evidence, symptoms): + return try assembly.convertECG( + ecg, + evidence: evidence, + symptoms: symptoms, + request: request, + symptomRequests: symptomRequests(plan, reserved: reserved) + ) + } + } + + /// Each registered symptom's request under its own reservation, looked up by its request, never by position. + private func symptomRequests( + _ plan: Plan, + reserved: [ExchangeEventRequest: ExchangeEventReservation] + ) throws -> HealthKitAssembly.SymptomRequests { + var requests: [UUID: HealthKitAssembly.Request] = [:] + for (symptom, planned) in zip(plan.input.symptoms, plan.symptoms) { + guard let planned, requests[symptom.uuid] == nil else { + continue + } + requests[symptom.uuid] = try request(for: symptom, reservation: reservation(for: planned, in: reserved)) } + return .keyed(requests) } /// An omission a policy chose is never reported. @@ -172,40 +266,21 @@ extension HealthKitFHIRExporter { } -@available(iOS 18, macOS 15, watchOS 11, *) -extension HealthKitFHIRExporter.Plan { - init(_ record: HealthKitFHIRExporter.Record) { - self.record = record - var keys: [ExchangeEventKey] = [] - if let key = ExchangeEventKey.active(record.sample) { - keys.append(key) - } - if case .electrocardiogram(_, _, let symptoms) = record { - keys += symptoms.compactMap(ExchangeEventKey.active) - } - self.keys = keys - self.refusal = keys.isEmpty ? .unregisteredSourceType(record.sample.sampleType.identifier) : nil - } -} - - @available(iOS 18, macOS 15, watchOS 11, *) extension HealthKitFHIRExporter { - /// One record's event and the policies the options resolve for its source. - func request( - for sample: HKSample, - reservation: ExchangeEventReservation, - producerInstance: UUID - ) throws -> HealthKitAssembly.Request { + /// One record's event, the facts frozen with it, and the policies the options resolve for its source. + func request(for sample: HKSample, reservation: ExchangeEventReservation) throws -> HealthKitAssembly.Request { let source = sample.sourceRevision.source return HealthKitAssembly.Request( event: try ExchangeEventIdentifier( system: producer.identityScope.systems.event, - producerInstance: producerInstance, + producerInstance: reservation.producerInstance, sequence: reservation.sequence ), instant: reservation.instant, - converterRole: options.role.converterRole(for: sample.sourceRevision, application: producer.application), + facts: reservation.facts, + // The gateway role compares the sample's revision with the build the event froze. + converterRole: options.role.converterRole(for: sample.sourceRevision, application: reservation.facts.application), repositoryIDs: try legacyRepositoryIDs(for: sample.uuid), options: HealthKitConversionOptions( writer: options.writer.classification(of: source), @@ -232,13 +307,15 @@ extension HealthKitFHIRExporter { extension ExchangeEventKey { /// The active-event key of a HealthKit sample: its source type and UUID, nothing else. static func active(_ sample: HKSample) -> ExchangeEventKey? { - guard let type = HealthKitSourceType(sample) else { - return nil - } - return ExchangeEventKey( + HealthKitSourceType(sample).map { active(type: $0, uuid: sample.uuid) } + } + + /// The active-event key of the record of `type` with `uuid`. + static func active(type: HealthKitSourceType, uuid: UUID) -> ExchangeEventKey { + ExchangeEventKey( kind: .active, adapterID: HealthKitConverter.adapterID, - sourceRecord: "\(type.rawValue)|\(sample.uuid.uuidString.lowercased())" + sourceRecord: "\(type.rawValue)|\(uuid.uuidString.lowercased())" ) } } diff --git a/Tests/GroveFHIRTests/ExchangeLedger/CountingStorage.swift b/Tests/GroveFHIRTests/ExchangeLedger/CountingStorage.swift new file mode 100644 index 000000000..c54d29a3d --- /dev/null +++ b/Tests/GroveFHIRTests/ExchangeLedger/CountingStorage.swift @@ -0,0 +1,89 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +import Foundation +import GroveFHIRContract + + +/// Counts the transactions a storage runs and the reads, writes, removals and listings inside them. +final class CountingStorage: ExchangeEventSequencer.Storage, @unchecked Sendable { // `counts` is guarded by `lock`. + struct Counts: Equatable { + var transactions = 0 + var reads = 0 + var writes = 0 + var removals = 0 + var listings = 0 + } + + private struct Counting: ExchangeEventSequencer.Transaction { + let base: any ExchangeEventSequencer.Transaction + let storage: CountingStorage + + func read(_ key: String) throws -> Data? { + storage.count { $0.reads += 1 } + return try base.read(key) + } + + func write(_ value: Data, for key: String) throws { + storage.count { $0.writes += 1 } + try base.write(value, for: key) + } + + func remove(_ key: String) throws { + storage.count { $0.removals += 1 } + try base.remove(key) + } + + func keys(prefixedBy prefix: String) throws -> [String] { + storage.count { $0.listings += 1 } + return try base.keys(prefixedBy: prefix) + } + } + + let base: any ExchangeEventSequencer.Storage + private let lock = NSLock() + private var counts = Counts() + + var snapshot: Counts { + lock.lock() + defer { + lock.unlock() + } + return counts + } + + init(_ base: any ExchangeEventSequencer.Storage = ExchangeEventSequencer.InMemoryStorage()) { + self.base = base + } + + func transaction(_ body: (any ExchangeEventSequencer.Transaction) throws -> R) throws -> R { + count { $0.transactions += 1 } + return try base.transaction { transaction in + try body(Counting(base: transaction, storage: self)) + } + } + + /// The counts since the last call, which starts a new tally. + func takeCounts() -> Counts { + lock.lock() + defer { + lock.unlock() + } + let taken = counts + counts = Counts() + return taken + } + + private func count(_ update: (inout Counts) -> Void) { + lock.lock() + defer { + lock.unlock() + } + update(&counts) + } +} diff --git a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldTests.swift b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldTests.swift new file mode 100644 index 000000000..feda3f1df --- /dev/null +++ b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldTests.swift @@ -0,0 +1,125 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +import Foundation +@testable import GroveFHIRContract +import Testing + + +/// Holds, releases, lapses and the receipts' transaction budget. +@Suite +struct ExchangeEventHoldTests { + private typealias Fixtures = LedgerFixtures + + private static func isReserved(_ request: ExchangeEventRequest, in storage: any ExchangeEventSequencer.Storage) throws -> Bool { + try Fixtures.stored(LedgerKey.event(request.key), in: storage) != nil + } + + @Test("G8: a lapsed hold keeps the reservation; the redelivery reuses event and facts and its release removes it") + func lapseKeepsTheReservation() throws { + let storage = ExchangeEventSequencer.InMemoryStorage() + let sequencer = Fixtures.sequencer(storage) + let request = Fixtures.request("a") + let first = try sequencer.reserve([request], at: Fixtures.instant, facts: Fixtures.facts(build: "100")) + try sequencer.finish(first.values.map(\.handle), released: false, forgetting: []) + #expect(try Self.isReserved(request, in: storage)) + let again = try sequencer.reserve([request], at: Fixtures.instant, facts: Fixtures.facts(build: "110")) + #expect(again == first) + try sequencer.finish(again.values.map(\.handle), released: true, forgetting: []) + #expect(try !Self.isReserved(request, in: storage)) + #expect(sequencer.holds.isEmpty) + } + + @Test("G8: after a crash between reserve and release, the next process reuses and removes the reservation") + func crashLeavesTheReservationForTheNextProcess() throws { + let storage = ExchangeEventSequencer.InMemoryStorage() + let request = Fixtures.request("a") + let first = try Fixtures.sequencer(storage).reserve([request], at: Fixtures.instant, facts: Fixtures.facts(build: "100")) + let restarted = Fixtures.sequencer(storage) + let again = try restarted.reserve([request], at: Fixtures.instant, facts: Fixtures.facts(build: "110")) + #expect(again == first) + try restarted.finish(again.values.map(\.handle), released: true, forgetting: []) + #expect(try !Self.isReserved(request, in: storage)) + } + + @Test("G9a: of two overlapping holders, the first release keeps the event and the last finisher removes it") + func overlappingHoldersRemoveOnLastFinish() throws { + let storage = ExchangeEventSequencer.InMemoryStorage() + let sequencer = Fixtures.sequencer(storage) + let request = Fixtures.request("a") + let live = try sequencer.reserve([request], at: Fixtures.instant, facts: Fixtures.facts()) + let bulk = try sequencer.reserve([request], at: Fixtures.instant, facts: Fixtures.facts()) + #expect(live == bulk) + try sequencer.finish(live.values.map(\.handle), released: true, forgetting: []) + #expect(try Self.isReserved(request, in: storage), "the slower call still holds the event") + #expect(try sequencer.reserve([request], at: Fixtures.instant, facts: Fixtures.facts()) == live, "its redelivery is an exact retry") + try sequencer.finish(live.values.map(\.handle), released: false, forgetting: []) + #expect(try Self.isReserved(request, in: storage)) + try sequencer.finish(bulk.values.map(\.handle), released: true, forgetting: []) + #expect(try !Self.isReserved(request, in: storage)) + } + + @Test("G9d: when the releasing holder finishes first and the other is dropped, the dropped one removes the event") + func lapseAfterAnotherReleaseRemoves() throws { + let storage = ExchangeEventSequencer.InMemoryStorage() + let sequencer = Fixtures.sequencer(storage) + let request = Fixtures.request("a") + let winner = try sequencer.reserve([request], at: Fixtures.instant, facts: Fixtures.facts()) + let loser = try sequencer.reserve([request], at: Fixtures.instant, facts: Fixtures.facts()) + try sequencer.finish(winner.values.map(\.handle), released: true, forgetting: []) + try sequencer.finish(loser.values.map(\.handle), released: false, forgetting: []) + #expect(try !Self.isReserved(request, in: storage)) + #expect(sequencer.holds.isEmpty) + } + + @Test("G10: a handle from before a reset releases nothing, and a replaced reservation is not removed") + func releaseIsOwned() throws { + let storage = ExchangeEventSequencer.InMemoryStorage() + let sequencer = Fixtures.sequencer(storage) + let request = Fixtures.request("a") + let before = try sequencer.reserve([request], at: Fixtures.instant, facts: Fixtures.facts()) + try sequencer.reset() + let after = try sequencer.reserve([request], at: Fixtures.instant, facts: Fixtures.facts()) + #expect(after[request]?.producerInstance != before[request]?.producerInstance) + #expect(after[request]?.sequence.rawValue == "1") + try sequencer.finish(before.values.map(\.handle), released: true, forgetting: []) + #expect(try Self.isReserved(request, in: storage)) + let replaced = Fixtures.request("a", fingerprint: "context-b") + let successor = try sequencer.reserve([replaced], at: Fixtures.instant, facts: Fixtures.facts()) + try sequencer.finish(after.values.map(\.handle), released: true, forgetting: []) + #expect(try Fixtures.sequencer(storage).reserve([replaced], at: Fixtures.instant, facts: Fixtures.facts()) == successor) + } + + @Test("G10: nothing to release opens no transaction; a reserve and its release take one each") + func releaseIsCheap() throws { + let storage = CountingStorage() + let sequencer = Fixtures.sequencer(storage) + try sequencer.finish([], released: true, forgetting: []) + try sequencer.finish([], released: false, forgetting: [Fixtures.key("a")]) + #expect(storage.takeCounts().transactions == 0) + let reserved = try sequencer.reserve([Fixtures.request("a"), Fixtures.request("b")], at: Fixtures.instant, facts: Fixtures.facts()) + try sequencer.finish(reserved.values.map(\.handle), released: true, forgetting: [Fixtures.key("c")]) + #expect(storage.takeCounts().transactions == 2) + let lapsed = try sequencer.reserve([Fixtures.request("d")], at: Fixtures.instant, facts: Fixtures.facts()) + _ = storage.takeCounts() + try sequencer.finish(lapsed.values.map(\.handle), released: false, forgetting: []) + #expect(storage.takeCounts().transactions == 0, "a lapse with no released holder touches nothing") + } + + @Test("Forgetting removes a key whatever it holds, and only on release") + func forgettingRemovesUnconditionally() throws { + let storage = ExchangeEventSequencer.InMemoryStorage() + let sequencer = Fixtures.sequencer(storage) + let active = Fixtures.request("a") + _ = try sequencer.reserve([active], at: Fixtures.instant, facts: Fixtures.facts()) + try sequencer.finish([], released: false, forgetting: [active.key]) + #expect(try Self.isReserved(active, in: storage)) + try sequencer.finish([], released: true, forgetting: [active.key]) + #expect(try !Self.isReserved(active, in: storage)) + } +} diff --git a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventSequencerTests.swift b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventSequencerTests.swift new file mode 100644 index 000000000..a965278bf --- /dev/null +++ b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventSequencerTests.swift @@ -0,0 +1,143 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +import Foundation +@testable import GroveFHIRContract +import Testing + + +/// The sequencer's reservation, hold, release, reset and pruning semantics over the in-memory storage. +@Suite +struct ExchangeEventSequencerTests { + private typealias Fixtures = LedgerFixtures + + private static func producer(in storage: any ExchangeEventSequencer.Storage) throws -> ProducerEntry? { + try Fixtures.stored(LedgerKey.producer, in: storage).map { try ProducerEntry(decoding: $0) } + } + + @Test("G1: new keys take 1..n in sorted request order, each naming the ledger's instance, at the millisecond instant") + func newKeysTakeConsecutiveSequences() throws { + let storage = ExchangeEventSequencer.InMemoryStorage() + let sequencer = Fixtures.sequencer(storage) + let requests = ["a", "b", "c", "d"].map { Fixtures.request($0) } + let reserved = try sequencer.reserve(requests, at: Fixtures.instant, facts: Fixtures.facts()) + let sorted = requests.sorted { $0.key.rawValue < $1.key.rawValue } + #expect(sorted.map { reserved[$0]?.sequence.rawValue } == ["1", "2", "3", "4"]) + let producer = try #require(try Self.producer(in: storage)) + #expect(producer.next == 5) + #expect(reserved.values.allSatisfy { $0.producerInstance == producer.instance && $0.handle.instance == producer.instance }) + #expect(reserved.values.allSatisfy { ExchangeInstant.millisecondsSinceEpoch($0.instant) == Fixtures.instantMilliseconds }) + let next = try sequencer.reserve([Fixtures.request("e")], at: Fixtures.instant, facts: Fixtures.facts()) + #expect(next.values.map(\.sequence.rawValue) == ["5"]) + } + + @Test("A reserved key under the same fingerprint returns its reservation and facts unchanged and writes nothing") + func reservedKeyIsReturnedUnchanged() throws { + let storage = CountingStorage() + let sequencer = Fixtures.sequencer(storage) + let request = Fixtures.request("a") + let first = try sequencer.reserve([request], at: Fixtures.instant, facts: Fixtures.facts(build: "100")) + _ = storage.takeCounts() + let again = try sequencer.reserve([request], at: Fixtures.instant.addingTimeInterval(3600), facts: Fixtures.facts(build: "110")) + #expect(again == first) + #expect(again[request]?.facts == (try Fixtures.facts(build: "100"))) + let counts = storage.takeCounts() + #expect(counts.writes == 0 && counts.removals == 0) + #expect(counts.transactions == 1) + } + + @Test("Equal requests in one call share a reservation; one key under two fingerprints is two events") + func requestsAreDistinctByFingerprint() throws { + let sequencer = Fixtures.sequencer() + let first = Fixtures.request("a", fingerprint: "bounds-1") + let second = Fixtures.request("a", fingerprint: "bounds-2") + let reserved = try sequencer.reserve([first, second, first], at: Fixtures.instant, facts: Fixtures.facts()) + #expect(reserved.count == 2) + #expect(reserved[first]?.sequence.rawValue == "1") + #expect(reserved[second]?.sequence.rawValue == "2") + // The later request replaced the stored reservation, so only it is reused. + let again = try sequencer.reserve([second], at: Fixtures.instant, facts: Fixtures.facts()) + #expect(again[second] == reserved[second]) + let changed = try sequencer.reserve([first], at: Fixtures.instant, facts: Fixtures.facts()) + #expect(changed[first]?.sequence.rawValue == "3", "a changed fingerprint takes a new sequence") + } + + @Test("An active event and its retraction never share a reservation") + func kindsDoNotShareReservations() throws { + let sequencer = Fixtures.sequencer() + let active = Fixtures.request("a", kind: .active) + let retraction = Fixtures.request("a", kind: .retraction) + #expect(active.key != retraction.key) + let reserved = try sequencer.reserve([active, retraction], at: Fixtures.instant, facts: Fixtures.facts()) + #expect(reserved[active]?.sequence != reserved[retraction]?.sequence) + } + + @Test("Sequencers over one storage share its producer instance and counter") + func sequencersShareOneLedger() throws { + let storage = ExchangeEventSequencer.InMemoryStorage() + let first = try Fixtures.sequencer(storage).reserve([Fixtures.request("a")], at: Fixtures.instant, facts: Fixtures.facts()) + let second = try Fixtures.sequencer(storage).reserve([Fixtures.request("b")], at: Fixtures.instant, facts: Fixtures.facts()) + #expect(first.values.first?.producerInstance == second.values.first?.producerInstance) + #expect(second.values.first?.sequence.rawValue == "2") + let other = try Fixtures.sequencer().reserve([Fixtures.request("a")], at: Fixtures.instant, facts: Fixtures.facts()) + #expect(other.values.first?.producerInstance != first.values.first?.producerInstance) + } + + @Test("The instant is kept at millisecond precision, the same the lexeme prints") + func instantIsKeptAtMillisecondPrecision() throws { + let sequencer = Fixtures.sequencer() + let inputs = [ + Date(timeIntervalSince1970: 1_791_023_400.2504), + Date(timeIntervalSince1970: 1_791_023_400.2506), + Date(timeIntervalSinceReferenceDate: 0.0015), + Date(timeIntervalSince1970: 1_791_023_400) + ] + for (index, input) in inputs.enumerated() { + let request = Fixtures.request("input-\(index)") + let reservation = try #require(try sequencer.reserve([request], at: input, facts: Fixtures.facts())[request]) + #expect(ExchangeInstant.utcLexeme(reservation.instant) == ExchangeInstant.utcLexeme(input)) + #expect(ExchangeInstant.millisecondsSinceEpoch(reservation.instant) == ExchangeInstant.millisecondsSinceEpoch(input)) + } + } + + @Test("Event keys are deterministic, opaque and distinct per kind, adapter, record and revision") + func eventKeysAreDeterministic() { + let key = ExchangeEventKey(kind: .active, adapterID: "healthkit", sourceRecord: "v0:test:1:abc") + #expect(key.rawValue == "QJYnsrPbiZst-026qKmvDi4tFo-IhLG57U8UgeV8dnA") + #expect(ExchangeEventKey(kind: .retraction, adapterID: "healthkit", sourceRecord: "v0:test:1:abc").rawValue + == "1DUNhw48VqO1miswNf2NyCKooKbEEJalqwILpnSnI1c") + #expect(ExchangeEventKey(kind: .active, adapterID: "healthkit", sourceRecord: "v0:test:1:abc", revision: "2").rawValue + == "LFumTOqgPPVowwziZlkJe38Fny6WhwuXWsybuA0q5NU") + #expect(ExchangeEventKey(kind: .active, adapterID: "health-connect", sourceRecord: "record|東京").rawValue + == "5KcJSfyiuPprLQxytaPUofKJanVJndVBMWcjPPlWdW4") + #expect(key != ExchangeEventKey(kind: .active, adapterID: "sensorkit", sourceRecord: "v0:test:1:abc")) + #expect(key != ExchangeEventKey(kind: .active, adapterID: "healthkit", sourceRecord: "v0:test:1:abc", revision: "")) + #expect(key.rawValue.utf8.count == 43) + #expect(LedgerKey.event(key).utf8.count <= 64 && LedgerKey.facts(key.rawValue).utf8.count <= 64) + // Framing, not delimiting: moving a boundary changes the key. + #expect(ExchangeEventKey(kind: .active, adapterID: "healthkita", sourceRecord: "bc") + != ExchangeEventKey(kind: .active, adapterID: "healthkit", sourceRecord: "abc")) + } + + @Test("The entries follow the documented layout") + func entriesFollowTheLayout() throws { + let storage = ExchangeEventSequencer.InMemoryStorage() + let request = Fixtures.request("a") + let reservation = try #require( + try Fixtures.sequencer(storage).reserve([request], at: Fixtures.instant, facts: Fixtures.facts())[request] + ) + let instance = reservation.producerInstance.uuidString.lowercased() + let producer = try #require(try Fixtures.stored(LedgerKey.producer, in: storage)) + #expect(String(decoding: producer, as: UTF8.self) == #"{"instance":"\#(instance)","next":"2","v":1}"#) + let event = try #require(try Fixtures.stored(LedgerKey.event(request.key), in: storage)) + let digest = try PreparedFacts(Fixtures.facts()).digest + #expect(String(decoding: event, as: UTF8.self) + == #"{"facts":"\#(digest)","fingerprint":"context-a","instance":"\#(instance)","instant":1791023400251,"sequence":"1","v":1}"#) + #expect(try Fixtures.keys("", in: storage) == [LedgerKey.producer, LedgerKey.event(request.key), LedgerKey.facts(digest)]) + } +} diff --git a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerEntryTests.swift b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerEntryTests.swift new file mode 100644 index 000000000..a4b9f1314 --- /dev/null +++ b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerEntryTests.swift @@ -0,0 +1,253 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +import Foundation +@testable import GroveFHIRContract +import Testing + + +/// A ledger whose `a` reservation or producer entry is corrupt or from a later layout. +struct CorruptLedger: Sendable, CustomTestStringConvertible { + static let all: [CorruptLedger] = [ + CorruptLedger(name: "non-JSON", event: "not json"), + CorruptLedger(name: "sequence zero", event: ExchangeLedgerEntryTests.event(sequence: "0")), + CorruptLedger(name: "non-canonical sequence", event: ExchangeLedgerEntryTests.event(sequence: "05")), + CorruptLedger(name: "sequence at the counter", event: ExchangeLedgerEntryTests.event(sequence: "7")), + CorruptLedger(name: "invalid instance", event: ExchangeLedgerEntryTests.event(instance: "not-a-uuid")), + CorruptLedger(name: "instance without a version", event: ExchangeLedgerEntryTests.event(instance: "00000000-0000-0000-0000-000000000000")), + CorruptLedger( + name: "no version", + event: #"{"facts":"","fingerprint":"x","instance":"\#(ExchangeLedgerEntryTests.instance)","instant":1,"sequence":"1"}"# + ), + CorruptLedger(name: "later version", event: ExchangeLedgerEntryTests.event(version: 2)), + CorruptLedger( + name: "counter zero", + event: ExchangeLedgerEntryTests.event(), + producer: #"{"instance":"\#(ExchangeLedgerEntryTests.instance)","next":"0","v":1}"# + ), + CorruptLedger( + name: "producer of a later version", + event: ExchangeLedgerEntryTests.event(), + producer: #"{"instance":"\#(ExchangeLedgerEntryTests.instance)","next":"9","v":3}"# + ) + ] + + let name: String + let event: String + var producer: String? + + var testDescription: String { name } +} + + +/// Stored entries: facts, reset, pruning, validation, atomicity and cost. +@Suite +struct ExchangeLedgerEntryTests { + private typealias Fixtures = LedgerFixtures + + fileprivate static let instance = "1f5c58aa-6ec6-4e79-a682-829a9debd3f5" + + /// A ledger holding one reservation for `a` under `instance`, with the current facts stored. + private static func seededLedger(event: String, producer: String? = nil) throws -> ExchangeEventSequencer.InMemoryStorage { + let storage = ExchangeEventSequencer.InMemoryStorage() + let facts = try PreparedFacts(Fixtures.facts()) + try storage.transaction { try $0.write(facts.bytes, for: LedgerKey.facts(facts.digest)) } + try Fixtures.seed( + [ + LedgerKey.producer: producer ?? #"{"instance":"\#(instance)","next":"7","v":1}"#, + LedgerKey.event(Fixtures.key("a")): event.replacingOccurrences(of: "", with: facts.digest) + ], + in: storage + ) + return storage + } + + fileprivate static func event(instance: String = Self.instance, sequence: String = "5", version: Int = 1) -> String { + #"{"facts":"","fingerprint":"context-a","instance":"\#(instance)","instant":1791023400251,"sequence":"\#(sequence)","v":\#(version)}"# + } + + @Test("G18: facts with several studies, a versioned canonical and absent host fields decode to themselves") + func factsRoundTrip() throws { + let studies = [ + try Fixtures.enrollment("a", protocolURL: "https://study.example.org/PlanDefinition/a|2.1"), + try Fixtures.enrollment("b", protocolURL: "https://study.example.org/PlanDefinition/b", version: "7") + ] + let facts = ExchangeEventFacts( + application: try ApplicationDevice(name: "Grove Test", bundleIdentifier: "org.grovealliance.test", version: "1.0"), + host: try HostDevice(operatingSystemVersion: "26.0.1"), + studies: studies + ) + let prepared = try PreparedFacts(facts) + #expect(prepared.facts == facts) + #expect(try PreparedFacts.decode(prepared.bytes, key: "facts/x") == facts) + #expect(try PreparedFacts(prepared.facts).bytes == prepared.bytes, "encoding is deterministic") + #expect(try PreparedFacts(Fixtures.facts(build: "101")).digest != prepared.digest) + let current = ExchangeEventFacts( + application: try ApplicationDevice(name: "Grove Test", bundleIdentifier: "org.grovealliance.test", version: "1.0"), + host: HostDevice.current(), + studies: [] + ) + #expect(try PreparedFacts(current).facts == current) + } + + @Test("Equal facts are stored once and shared across reservations and instances") + func factsAreDeduplicated() throws { + let storage = ExchangeEventSequencer.InMemoryStorage() + let sequencer = Fixtures.sequencer(storage) + _ = try sequencer.reserve([Fixtures.request("a"), Fixtures.request("b")], at: Fixtures.instant, facts: Fixtures.facts()) + _ = try sequencer.reserve([Fixtures.request("c")], at: Fixtures.instant, facts: Fixtures.facts()) + #expect(try Fixtures.keys(LedgerKey.factsPrefix, in: storage).count == 1) + _ = try sequencer.reserve([Fixtures.request("d")], at: Fixtures.instant, facts: Fixtures.facts(build: "101")) + #expect(try Fixtures.keys(LedgerKey.factsPrefix, in: storage).count == 2) + } + + @Test("G12: reset mints a new instance numbering from one, forgets the facts, and old handles are no-ops") + func resetStartsOver() throws { + let storage = ExchangeEventSequencer.InMemoryStorage() + let sequencer = Fixtures.sequencer(storage) + let old = try sequencer.reserve([Fixtures.request("a"), Fixtures.request("b")], at: Fixtures.instant, facts: Fixtures.facts()) + try sequencer.reset() + #expect(try Fixtures.keys("", in: storage).isEmpty) + let fresh = try sequencer.reserve([Fixtures.request("b")], at: Fixtures.instant, facts: Fixtures.facts()) + let reservation = try #require(fresh.values.first) + #expect(reservation.sequence.rawValue == "1") + #expect(!old.values.contains { $0.producerInstance == reservation.producerInstance }) + try sequencer.finish(old.values.map(\.handle), released: true, forgetting: []) + #expect(try sequencer.reserve([Fixtures.request("b")], at: Fixtures.instant, facts: Fixtures.facts()) == fresh) + } + + @Test("G13: forgetting removes reservations made before the cutoff and the facts nothing references") + func forgettingPrunesExplicitly() throws { + let storage = ExchangeEventSequencer.InMemoryStorage() + let sequencer = Fixtures.sequencer(storage) + let start = Fixtures.instant + _ = try sequencer.reserve([Fixtures.request("old-1"), Fixtures.request("old-2")], at: start, facts: Fixtures.facts(build: "1")) + _ = try sequencer.reserve([Fixtures.request("mid")], at: start + 60, facts: Fixtures.facts(build: "2")) + let kept = try sequencer.reserve([Fixtures.request("new")], at: start + 120, facts: Fixtures.facts(build: "2")) + #expect(try sequencer.forgetReservations(madeBefore: start) == 0) + #expect(try sequencer.forgetReservations(madeBefore: start + 60) == 2) + #expect(try Fixtures.keys(LedgerKey.factsPrefix, in: storage) == [LedgerKey.facts(try PreparedFacts(Fixtures.facts(build: "2")).digest)]) + #expect(try sequencer.forgetReservations(madeBefore: start + 61) == 1) + #expect(try Fixtures.keys(LedgerKey.eventPrefix, in: storage) == [LedgerKey.event(Fixtures.key("new"))]) + #expect(try sequencer.reserve([Fixtures.request("new")], at: start + 500, facts: Fixtures.facts(build: "3")) == kept) + let renewed = try sequencer.reserve([Fixtures.request("old-1")], at: start + 500, facts: Fixtures.facts()) + #expect(renewed.values.first?.sequence.rawValue == "5", "a forgotten key is a new event; no sequence is reused") + } + + @Test("G14: corrupt and future entries throw typed errors, never trap, and reset recovers", arguments: CorruptLedger.all) + func corruptEntriesAreRefused(_ corrupt: CorruptLedger) throws { + let storage = try Self.seededLedger(event: corrupt.event, producer: corrupt.producer) + let sequencer = Fixtures.sequencer(storage) + #expect(throws: ExchangeEventSequencer.LedgerError.self, "\(corrupt.name)") { + try sequencer.reserve([Fixtures.request("a")], at: Fixtures.instant, facts: Fixtures.facts()) + } + try sequencer.reset() + let recovered = try sequencer.reserve([Fixtures.request("a")], at: Fixtures.instant, facts: Fixtures.facts()) + #expect(recovered.values.first?.sequence.rawValue == "1") + } + + @Test("G14: each fault names its entry and kind") + func faultsAreTyped() throws { + let eventKey = LedgerKey.event(Fixtures.key("a")) + let request = Fixtures.request("a") + let facts = try Fixtures.facts() + let future = Fixtures.sequencer(try Self.seededLedger(event: Self.event(version: 2))) + #expect(throws: ExchangeEventSequencer.LedgerError.unsupportedEntryVersion(key: eventKey, version: 2)) { + try future.reserve([request], at: Fixtures.instant, facts: facts) + } + let regressed = Fixtures.sequencer(try Self.seededLedger(event: Self.event(sequence: "8"))) + #expect(throws: ExchangeEventSequencer.LedgerError.corruptEntry(key: eventKey)) { + try regressed.reserve([request], at: Fixtures.instant, facts: facts) + } + let retired = try Self.seededLedger(event: Self.event(instance: "2eafba7b-4c21-4bf5-ad46-351b0176b25a", sequence: "8")) + #expect(try Fixtures.sequencer(retired).reserve([request], at: Fixtures.instant, facts: facts)[request]?.sequence.rawValue == "8") + let missingFacts = try Self.seededLedger(event: Self.event()) + try missingFacts.transaction { try $0.remove(LedgerKey.facts(try PreparedFacts(facts).digest)) } + #expect(throws: ExchangeEventSequencer.LedgerError.corruptEntry(key: eventKey)) { + try Fixtures.sequencer(missingFacts).reserve([request], at: Fixtures.instant, facts: facts) + } + let blankName = try Self.seededLedger(event: Self.event()) + let factsKey = LedgerKey.facts(try PreparedFacts(facts).digest) + let stored = String(decoding: try #require(try Fixtures.stored(factsKey, in: blankName)), as: UTF8.self) + try Fixtures.seed([factsKey: stored.replacingOccurrences(of: #""name":"Grove Test""#, with: #""name":" ""#)], in: blankName) + #expect(throws: ExchangeEventSequencer.LedgerError.corruptEntry(key: factsKey)) { + try Fixtures.sequencer(blankName).reserve([request], at: Fixtures.instant, facts: facts) + } + #expect(throws: ExchangeEventSequencer.LedgerError.corruptEntry(key: eventKey)) { + try Fixtures.sequencer(try Self.seededLedger(event: "[]")).forgetReservations(madeBefore: Fixtures.instant) + } + } + + @Test("A reservation under a retired instance stays valid; an overflowing counter mints a new instance") + func counterOverflowRotatesTheInstance() throws { + let storage = try Self.seededLedger( + event: Self.event(sequence: "5"), + producer: #"{"instance":"\#(Self.instance)","next":"18446744073709551615","v":1}"# + ) + let sequencer = Fixtures.sequencer(storage) + let reserved = try sequencer.reserve([Fixtures.request("a"), Fixtures.request("b")], at: Fixtures.instant, facts: Fixtures.facts()) + #expect(reserved[Fixtures.request("a")]?.sequence.rawValue == "5") + let rotated = try #require(reserved[Fixtures.request("b")]) + #expect(rotated.sequence.rawValue == "1") + #expect(rotated.producerInstance.uuidString.lowercased() != Self.instance) + } + + @Test("G7: a failure mid-reserve or at commit stores nothing and holds nothing; a retry numbers consecutively") + func failuresAreAtomic() throws { + let storage = FaultyStorage() + let sequencer = Fixtures.sequencer(storage) + _ = try sequencer.reserve([Fixtures.request("a")], at: Fixtures.instant, facts: Fixtures.facts()) + let before = try Fixtures.keys("", in: storage.base) + let requests = ["b", "c", "d"].map { Fixtures.request($0) } + for write in 1...4 { + storage.failWrite(write) + #expect(throws: FaultyStorage.Fault()) { + try sequencer.reserve(requests, at: Fixtures.instant, facts: Fixtures.facts(build: "200")) + } + } + storage.failWrite(nil) + storage.failAtCommit(true) + #expect(throws: FaultyStorage.Fault()) { + try sequencer.reserve(requests, at: Fixtures.instant, facts: Fixtures.facts(build: "200")) + } + storage.failAtCommit(false) + #expect(try Fixtures.keys("", in: storage.base) == before) + #expect(sequencer.holds.count == 1, "only the first call's hold") + let retried = try sequencer.reserve(requests, at: Fixtures.instant, facts: Fixtures.facts(build: "200")) + #expect(Set(retried.values.map(\.sequence.rawValue)) == ["2", "3", "4"]) + } + + @Test("Storage errors propagate from reserve, finish, reset and forgetting; a failed release keeps the reservation") + func storageErrorsPropagate() throws { + let storage = FaultyStorage() + let sequencer = Fixtures.sequencer(storage) + let reserved = try sequencer.reserve([Fixtures.request("a")], at: Fixtures.instant, facts: Fixtures.facts()) + storage.failAtCommit(true) + #expect(throws: FaultyStorage.Fault()) { try sequencer.finish(reserved.values.map(\.handle), released: true, forgetting: []) } + #expect(throws: FaultyStorage.Fault()) { try sequencer.reset() } + #expect(throws: FaultyStorage.Fault()) { try sequencer.forgetReservations(madeBefore: .distantFuture) } + storage.failAtCommit(false) + #expect(try sequencer.reserve([Fixtures.request("a")], at: Fixtures.instant, facts: Fixtures.facts()) == reserved) + } + + @Test("G15: an export's cost does not depend on the ledger's size") + func costIsIndependentOfLedgerSize() throws { + let storage = CountingStorage() + let sequencer = Fixtures.sequencer(storage) + let seeded = (0..<100_000).map { Fixtures.request("seed-\($0)") } + _ = try sequencer.reserve(seeded, at: Fixtures.instant, facts: Fixtures.facts()) + _ = storage.takeCounts() + let fresh = ["x", "y", "z"].map { Fixtures.request($0) } + _ = try sequencer.reserve(fresh, at: Fixtures.instant, facts: Fixtures.facts()) + let minting = storage.takeCounts() + #expect(minting.transactions == 1 && minting.reads <= 5 && minting.writes <= 5 && minting.listings == 0) + _ = try sequencer.reserve(fresh, at: Fixtures.instant, facts: Fixtures.facts()) + let reusing = storage.takeCounts() + #expect(reusing.transactions == 1 && reusing.reads <= 5 && reusing.writes == 0 && reusing.listings == 0) + } +} diff --git a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerPropertyTests.swift b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerPropertyTests.swift new file mode 100644 index 000000000..6c7c81107 --- /dev/null +++ b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerPropertyTests.swift @@ -0,0 +1,159 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +import Foundation +@testable import GroveFHIRContract +import Testing + + +/// SplitMix64: a seeded generator, so a failing interleaving reproduces. +private struct SeededGenerator: RandomNumberGenerator { + private var state: UInt64 + + init(seed: UInt64) { + state = seed + } + + mutating func next() -> UInt64 { + state &+= 0x9E37_79B9_7F4A_7C15 + var value = state + value = (value ^ (value >> 30)) &* 0xBF58_476D_1CE4_E5B9 + value = (value ^ (value >> 27)) &* 0x94D0_49BB_1331_11EB + return value ^ (value >> 31) + } +} + + +/// Maps every handed-out (instance, sequence) to what it was handed out for; a second, different use is a reuse. +private final class ReuseOracle: @unchecked Sendable { // `events` and `reuses` are guarded by `lock`. + struct Event: Equatable { + let key: ExchangeEventKey + let fingerprint: String + let instant: Date + let facts: ExchangeEventFacts + } + + private struct Identifier: Hashable { + let instance: UUID + let sequence: UInt64 + } + + private let lock = NSLock() + private var events: [Identifier: Event] = [:] + private(set) var reuses: [String] = [] + private(set) var observed = 0 + + func record(_ reserved: [ExchangeEventRequest: ExchangeEventReservation]) { + lock.lock() + defer { + lock.unlock() + } + for (request, reservation) in reserved { + observed += 1 + let identifier = Identifier(instance: reservation.handle.instance, sequence: reservation.handle.sequence) + let event = Event(key: request.key, fingerprint: request.fingerprint, instant: reservation.instant, facts: reservation.facts) + if let earlier = events[identifier], earlier != event { + reuses.append("\(identifier.instance):\(identifier.sequence)") + } + events[identifier] = event + } + } +} + + +/// Sequences are never reused, under any interleaving and under concurrency. +@Suite +struct ExchangeLedgerPropertyTests { + private typealias Fixtures = LedgerFixtures + + /// One random step of the interleaving. + private static func step( + _ random: inout SeededGenerator, + sequencer: inout ExchangeEventSequencer, + storage: ExchangeEventSequencer.InMemoryStorage, + pending: inout [[ExchangeEventReservation.Handle]], + oracle: ReuseOracle + ) throws { + let keys = ["a", "b", "c", "d", "e", "f"] + let instant = Fixtures.instant.addingTimeInterval(Double(Int.random(in: 0..<100, using: &random))) + switch Int.random(in: 0..<100, using: &random) { + case 0..<45: + let requests = keys.filter { _ in Bool.random(using: &random) }.map { key in + Fixtures.request(key, fingerprint: ["context-a", "context-b"].randomElement(using: &random) ?? "context-a") + } + let facts = try Fixtures.facts(build: String(Int.random(in: 1...3, using: &random))) + let reserved = try sequencer.reserve(requests, at: instant, facts: facts) + oracle.record(reserved) + pending.append(reserved.values.map(\.handle)) + case 45..<65 where !pending.isEmpty: + let forgetting = keys.filter { _ in Int.random(in: 0..<6, using: &random) == 0 }.map { Fixtures.key($0) } + try sequencer.finish(pending.remove(at: Int.random(in: 0.. 1_000) + #expect(oracle.reuses.isEmpty, "reused: \(oracle.reuses.prefix(5))") + } + + @Test("G6: concurrent reservations and releases with a resetting thread never collide", arguments: [false, true]) + func concurrentCallsNeverCollide(overFile: Bool) async throws { + let directory = FileManager.default.temporaryDirectory.appendingPathComponent("ledger-\(UUID().uuidString)", isDirectory: true) + defer { + try? FileManager.default.removeItem(at: directory) + } + let storage: any ExchangeEventSequencer.Storage = overFile ? try FileStorage(directory: directory) : ExchangeEventSequencer.InMemoryStorage() + let sequencer = Fixtures.sequencer(storage) + let oracle = ReuseOracle() + let threads = 8 + let calls = 200 + try await withThrowingTaskGroup(of: Void.self) { group in + for thread in 0.. Data? { + try base.read(key) + } + + func write(_ value: Data, for key: String) throws { + writes += 1 + if writes == failingWrite { + throw Fault() + } + try base.write(value, for: key) + } + + func remove(_ key: String) throws { + try base.remove(key) + } + + func keys(prefixedBy prefix: String) throws -> [String] { + try base.keys(prefixedBy: prefix) + } + } + + let base = ExchangeEventSequencer.InMemoryStorage() + private let lock = NSLock() + private var failingWrite: Int? + private var failsAtCommit = false + + /// Makes the `write`-th write of every later transaction throw; `nil` stops it. + func failWrite(_ write: Int?) { + lock.lock() + defer { + lock.unlock() + } + failingWrite = write + } + + /// Makes every later transaction fail after its body returned, so nothing it wrote commits. + func failAtCommit(_ fails: Bool) { + lock.lock() + defer { + lock.unlock() + } + failsAtCommit = fails + } + + func transaction(_ body: (any ExchangeEventSequencer.Transaction) throws -> R) throws -> R { + lock.lock() + let (failingWrite, failsAtCommit) = (self.failingWrite, self.failsAtCommit) + lock.unlock() + return try base.transaction { transaction in + let result = try body(Faulting(base: transaction, failingWrite: failingWrite)) + // Throwing from inside the base transaction discards its buffered writes: a failed commit. + if failsAtCommit { + throw Fault() + } + return result + } + } +} diff --git a/Tests/GroveFHIRTests/ExchangeLedger/FileStorage.swift b/Tests/GroveFHIRTests/ExchangeLedger/FileStorage.swift new file mode 100644 index 000000000..638b32b27 --- /dev/null +++ b/Tests/GroveFHIRTests/ExchangeLedger/FileStorage.swift @@ -0,0 +1,138 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(Darwin) +import Darwin +#elseif canImport(Glibc) +import Glibc +#endif +import Foundation +import GroveFHIRContract + + +/// A single-file storage per the contract's backend table: the map is a binary property list rewritten +/// atomically through a synced temporary file and a rename, serialised by a process lock and by `flock` on a +/// sibling lock file that is never replaced. +final class FileStorage: ExchangeEventSequencer.Storage, @unchecked Sendable { // The file is guarded by `lock` and `flock`. + struct IOFailure: Error, Equatable { + let operation: String + } + + private final class Snapshot: ExchangeEventSequencer.Transaction { + var entries: [String: Data] + var changed = false + + init(entries: [String: Data]) { + self.entries = entries + } + + func read(_ key: String) throws -> Data? { + entries[key] + } + + func write(_ value: Data, for key: String) throws { + entries[key] = value + changed = true + } + + func remove(_ key: String) throws { + if entries.removeValue(forKey: key) != nil { + changed = true + } + } + + func keys(prefixedBy prefix: String) throws -> [String] { + entries.keys.filter { $0.hasPrefix(prefix) } + } + } + + let directory: URL + private let lock = NSLock() + + private var ledgerURL: URL { directory.appendingPathComponent("ledger.plist") } + private var lockURL: URL { directory.appendingPathComponent("ledger.lock") } + + init(directory: URL) throws { + self.directory = directory + try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true) + } + + /// Flushes the file to stable storage; on Darwin that takes `F_FULLFSYNC`, as `fsync` leaves the device cache. + private static func synchronize(_ descriptor: Int32) -> Bool { + #if canImport(Darwin) + fcntl(descriptor, F_FULLFSYNC) == 0 + #else + fsync(descriptor) == 0 + #endif + } + + func transaction(_ body: (any ExchangeEventSequencer.Transaction) throws -> R) throws -> R { + lock.lock() + defer { + lock.unlock() + } + let lockDescriptor = open(lockURL.path, O_RDWR | O_CREAT, 0o600) + guard lockDescriptor >= 0 else { + throw IOFailure(operation: "open lock") + } + defer { + close(lockDescriptor) + } + guard flock(lockDescriptor, LOCK_EX) == 0 else { + throw IOFailure(operation: "flock") + } + defer { + flock(lockDescriptor, LOCK_UN) + } + let snapshot = Snapshot(entries: try load()) + let result = try body(snapshot) + if snapshot.changed { + try store(snapshot.entries) + } + return result + } + + private func load() throws -> [String: Data] { + guard FileManager.default.fileExists(atPath: ledgerURL.path) else { + return [:] + } + return try PropertyListDecoder().decode([String: Data].self, from: Data(contentsOf: ledgerURL)) + } + + private func store(_ entries: [String: Data]) throws { + let encoder = PropertyListEncoder() + encoder.outputFormat = .binary + let bytes = try encoder.encode(entries) + let temporaryURL = directory.appendingPathComponent("ledger.plist.tmp") + let descriptor = open(temporaryURL.path, O_WRONLY | O_CREAT | O_TRUNC, 0o600) + guard descriptor >= 0 else { + throw IOFailure(operation: "open temporary") + } + let written = bytes.withUnsafeBytes { buffer in + buffer.baseAddress.map { write(descriptor, $0, buffer.count) } ?? 0 + } + guard written == bytes.count, Self.synchronize(descriptor) else { + close(descriptor) + throw IOFailure(operation: "write temporary") + } + close(descriptor) + guard rename(temporaryURL.path, ledgerURL.path) == 0 else { + throw IOFailure(operation: "rename") + } + let directoryDescriptor = open(directory.path, O_RDONLY) + guard directoryDescriptor >= 0 else { + throw IOFailure(operation: "open directory") + } + defer { + close(directoryDescriptor) + } + guard fsync(directoryDescriptor) == 0 else { + throw IOFailure(operation: "sync directory") + } + } +} diff --git a/Tests/GroveFHIRTests/ExchangeLedger/LedgerFixtures.swift b/Tests/GroveFHIRTests/ExchangeLedger/LedgerFixtures.swift new file mode 100644 index 000000000..1782ae059 --- /dev/null +++ b/Tests/GroveFHIRTests/ExchangeLedger/LedgerFixtures.swift @@ -0,0 +1,76 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +import Foundation +@testable import GroveFHIRContract +import ModelsR4 + + +/// Fixtures the ledger tests share. +enum LedgerFixtures { + struct InvalidCanonical: Error {} + + static let instant = Date(timeIntervalSince1970: 1_791_023_400.251) + static let instantMilliseconds: Int64 = 1_791_023_400_251 + + static func key(_ record: String, kind: ExchangeGraph.Kind = .active) -> ExchangeEventKey { + ExchangeEventKey(kind: kind, adapterID: "healthkit", sourceRecord: record) + } + + static func request(_ record: String, fingerprint: String = "context-a", kind: ExchangeGraph.Kind = .active) -> ExchangeEventRequest { + ExchangeEventRequest(key: key(record, kind: kind), fingerprint: fingerprint) + } + + /// Facts naming application build `build`, so tests can tell facts apart. + static func facts(build: String = "100", operatingSystem: String = "26.0", studies: [StudyEnrollment] = []) throws -> ExchangeEventFacts { + ExchangeEventFacts( + application: try ApplicationDevice(name: "Grove Test", bundleIdentifier: "org.grovealliance.test", version: "1.0", build: build), + host: try HostDevice(operatingSystemVersion: operatingSystem, name: "Host", manufacturer: "Example", modelNumber: "Phone1"), + studies: studies + ) + } + + static func enrollment(_ name: String, protocolURL: String, version: String = "1") throws -> StudyEnrollment { + let system: IdentifierSystem = "https://study.example.org/fhir/study" + let enrollments: IdentifierSystem = "https://study.example.org/fhir/enrollment" + guard let canonical = protocolURL.asFHIRCanonicalPrimitive() else { + throw InvalidCanonical() + } + return try StudyEnrollment( + study: BusinessIdentifier(system: system, value: name), + protocolURL: canonical, + protocolVersion: version, + enrollment: BusinessIdentifier(system: enrollments, value: "\(name)-p-1") + ) + } + + /// A sequencer with its own hold registry, so a test sees only its own holds; a new registry over the + /// same storage simulates a new process. + static func sequencer(_ storage: any ExchangeEventSequencer.Storage = ExchangeEventSequencer.InMemoryStorage()) -> ExchangeEventSequencer { + ExchangeEventSequencer(storage: storage, holds: HoldRegistry()) + } + + /// The raw value stored under `key`. + static func stored(_ key: String, in storage: any ExchangeEventSequencer.Storage) throws -> Data? { + try storage.transaction { try $0.read(key) } + } + + /// Writes raw entries, bypassing the sequencer. + static func seed(_ entries: [String: String], in storage: any ExchangeEventSequencer.Storage) throws { + try storage.transaction { transaction in + for (key, value) in entries { + try transaction.write(Data(value.utf8), for: key) + } + } + } + + /// Every stored key under `prefix`. + static func keys(_ prefix: String, in storage: any ExchangeEventSequencer.Storage) throws -> Set { + Set(try storage.transaction { try $0.keys(prefixedBy: prefix) }) + } +} diff --git a/Tests/GroveHealthKitFHIRTests/ExchangeEventSequencerTests.swift b/Tests/GroveHealthKitFHIRTests/ExchangeEventSequencerTests.swift deleted file mode 100644 index 9dc467612..000000000 --- a/Tests/GroveHealthKitFHIRTests/ExchangeEventSequencerTests.swift +++ /dev/null @@ -1,325 +0,0 @@ -// -// This source file is part of the Grove open-source project -// -// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) -// -// SPDX-License-Identifier: MIT -// - -import Foundation -@testable import GroveFHIRContract -import Synchronization -import Testing - - -/// A storage that keeps the blob in memory, counts its writes, and can be reset or made to fail. -private final class LedgerStorage: ExchangeEventSequencer.Storage { - struct Failure: Error, Equatable {} - - private struct Ledger { - var data: Data? - var writes = 0 - var failing = false - } - - private let state = Mutex(Ledger()) - - var data: Data? { state.withLock { $0.data } } - var writes: Int { state.withLock { $0.writes } } - - func update(_ body: (inout Data?) throws -> R) throws -> R { - try state.withLock { stored in - guard !stored.failing else { - throw Failure() - } - var data = stored.data - let result = try body(&data) - if data != stored.data { - stored.data = data - stored.writes += 1 - } - return result - } - } - - func reset() { - state.withLock { $0 = Ledger(data: nil, writes: $0.writes, failing: false) } - } - - func fail(_ failing: Bool) { - state.withLock { $0.failing = failing } - } - - func seed(_ json: String) { - state.withLock { $0.data = Data(json.utf8) } - } -} - - -@Suite -struct ExchangeEventSequencerTests { - private static let instant = Date(timeIntervalSince1970: 1_791_023_400.251) - - private static func key(_ record: String, kind: ExchangeGraph.Kind = .active, revision: String? = nil) -> ExchangeEventKey { - ExchangeEventKey(kind: kind, adapterID: "healthkit", sourceRecord: record, revision: revision) - } - - @Test("New keys take consecutive sequences in input order, at the millisecond instant") - func newKeysTakeConsecutiveSequences() throws { - let sequencer = ExchangeEventSequencer.inMemory() - let reservations = try sequencer.reserve([Self.key("a"), Self.key("b"), Self.key("c")], at: Self.instant) - #expect(reservations.map(\.sequence.rawValue) == ["1", "2", "3"]) - #expect(reservations.map(\.instant) == Array(repeating: ExchangeInstant.date(millisecondsSinceEpoch: 1_791_023_400_251), count: 3)) - #expect(try sequencer.reserve([Self.key("d")], at: Self.instant).map(\.sequence.rawValue) == ["4"]) - } - - @Test("A reserved key returns the same sequence and instant, whatever the later instant") - func reservedKeyIsReturnedUnchanged() throws { - let sequencer = ExchangeEventSequencer.inMemory() - let first = try sequencer.reserve([Self.key("a")], at: Self.instant) - let again = try sequencer.reserve([Self.key("a")], at: Self.instant.addingTimeInterval(3600)) - #expect(again == first) - #expect(ExchangeInstant.millisecondsSinceEpoch(again[0].instant) == 1_791_023_400_251) - #expect(try sequencer.reserve([Self.key("b")], at: Self.instant).map(\.sequence.rawValue) == ["2"]) - } - - @Test("After release the key takes a new sequence; a sequence is never reused") - func releasedKeyTakesNewSequence() throws { - let sequencer = ExchangeEventSequencer.inMemory() - let first = try sequencer.reserve([Self.key("a"), Self.key("b")], at: Self.instant) - try sequencer.release([Self.key("a")]) - let second = try sequencer.reserve([Self.key("a"), Self.key("b")], at: Self.instant) - #expect(second[0].sequence.rawValue == "3") - #expect(second[1] == first[1]) - try sequencer.release([Self.key("a"), Self.key("b"), Self.key("never-reserved")]) - try sequencer.release([]) - #expect(try sequencer.reserve([Self.key("b")], at: Self.instant).map(\.sequence.rawValue) == ["4"]) - } - - @Test("An active event and its retraction never share a reservation") - func kindsDoNotShareReservations() throws { - let sequencer = ExchangeEventSequencer.inMemory() - let active = Self.key("a", kind: .active) - let retraction = Self.key("a", kind: .retraction) - #expect(active != retraction) - let reservations = try sequencer.reserve([active, retraction], at: Self.instant) - #expect(reservations[0].sequence != reservations[1].sequence) - } - - @Test("Duplicate keys in one call map to one reservation") - func duplicateKeysShareOneReservation() throws { - let sequencer = ExchangeEventSequencer.inMemory() - let reservations = try sequencer.reserve([Self.key("a"), Self.key("a"), Self.key("b"), Self.key("a")], at: Self.instant) - #expect(reservations.map(\.sequence.rawValue) == ["1", "1", "2", "1"]) - #expect(reservations[0] == reservations[1]) - } - - @Test("The producer instance is minted once and shared by every sequencer over the same storage") - func producerInstanceIsStableOverOneStorage() throws { - let storage = LedgerStorage() - let first = ExchangeEventSequencer(storage: storage) - let second = ExchangeEventSequencer(storage: storage) - let instance = try first.producerInstance - #expect(try second.producerInstance == instance) - #expect(try first.producerInstance == instance) - #expect(storage.writes == 1, "the first read persists the minted instance; later reads do not rewrite") - _ = try second.reserve([Self.key("a")], at: Self.instant) - #expect(try ExchangeEventSequencer(storage: storage).producerInstance == instance) - #expect(try ExchangeEventSequencer.inMemory().producerInstance != instance) - } - - @Test("Reservations are durable before reserve returns, and an exact retry does not rewrite the ledger") - func reservationsAreDurable() throws { - let storage = LedgerStorage() - let sequencer = ExchangeEventSequencer(storage: storage) - let reserved = try sequencer.reserve([Self.key("a"), Self.key("b")], at: Self.instant) - #expect(storage.writes == 1) - let fromStorage = try ExchangeEventSequencer(storage: storage).reserve([Self.key("b"), Self.key("a")], at: Self.instant.addingTimeInterval(60)) - #expect(fromStorage == [reserved[1], reserved[0]]) - #expect(storage.writes == 1) - let stored = try #require(storage.data) - let state = try JSONDecoder().decode(ExchangeEventSequencer.State.self, from: stored) - #expect(state.schemaVersion == ExchangeEventSequencer.State.currentSchemaVersion) - #expect(state.nextSequence == 3) - #expect(state.reservations.keys.sorted() == [Self.key("a").rawValue, Self.key("b").rawValue].sorted()) - #expect(state.reservations[Self.key("a").rawValue]?.instantMilliseconds == 1_791_023_400_251) - #expect(state.reservations[Self.key("a").rawValue]?.reservedAtMilliseconds == 1_791_023_400_251) - } - - @Test("A storage that restarts from nil yields a new producer instance numbering from one") - func resetStorageYieldsNewProducerInstance() throws { - let storage = LedgerStorage() - let sequencer = ExchangeEventSequencer(storage: storage) - let before = try sequencer.producerInstance - _ = try sequencer.reserve([Self.key("a"), Self.key("b")], at: Self.instant) - storage.reset() - let after = try sequencer.producerInstance - #expect(after != before) - let reservations = try sequencer.reserve([Self.key("a")], at: Self.instant) - #expect(reservations.map(\.sequence.rawValue) == ["1"]) - #expect(try sequencer.producerInstance == after) - } - - @Test("Reservations older than the retention are forgotten at the next reservation") - func retentionPrunesOldReservations() throws { - let sequencer = ExchangeEventSequencer.inMemory(retention: .init(maximumAge: 60)) - let first = try sequencer.reserve([Self.key("a")], at: Self.instant) - #expect(try sequencer.reserve([Self.key("a")], at: Self.instant.addingTimeInterval(59.999)) == first) - #expect(try sequencer.reserve([Self.key("b")], at: Self.instant.addingTimeInterval(60)).map(\.sequence.rawValue) == ["2"]) - #expect(try sequencer.reserve([Self.key("a")], at: Self.instant.addingTimeInterval(60)) == first, "exactly the retention old is kept") - _ = try sequencer.reserve([Self.key("c")], at: Self.instant.addingTimeInterval(60.001)) - let renewed = try sequencer.reserve([Self.key("a")], at: Self.instant.addingTimeInterval(60.002)) - #expect(renewed[0].sequence.rawValue == "4") - #expect(ExchangeInstant.millisecondsSinceEpoch(renewed[0].instant) == ExchangeInstant.millisecondsSinceEpoch(Self.instant.addingTimeInterval(60.002))) - #expect(try sequencer.reserve([Self.key("b")], at: Self.instant.addingTimeInterval(60.002)).map(\.sequence.rawValue) == ["2"]) - } - - @Test("The default retention keeps a reservation for thirty days") - func defaultRetention() throws { - #expect(ExchangeEventSequencer.Retention.default.maximumAge == 30 * 24 * 60 * 60) - let sequencer = ExchangeEventSequencer.inMemory() - #expect(sequencer.retention == .default) - let first = try sequencer.reserve([Self.key("a")], at: Self.instant) - #expect(try sequencer.reserve([Self.key("a")], at: Self.instant.addingTimeInterval(29 * 24 * 60 * 60)) == first) - _ = try sequencer.reserve([Self.key("b")], at: Self.instant.addingTimeInterval(31 * 24 * 60 * 60)) - #expect(try sequencer.reserve([Self.key("a")], at: Self.instant.addingTimeInterval(31 * 24 * 60 * 60)) != first) - } - - @Test("Storage errors propagate from reserve and release; the ignoring variant swallows them") - func storageErrorsPropagate() throws { - let storage = LedgerStorage() - let sequencer = ExchangeEventSequencer(storage: storage) - _ = try sequencer.reserve([Self.key("a")], at: Self.instant) - storage.fail(true) - #expect(throws: LedgerStorage.Failure()) { try sequencer.reserve([Self.key("b")], at: Self.instant) } - #expect(throws: LedgerStorage.Failure()) { try sequencer.release([Self.key("a")]) } - #expect(throws: LedgerStorage.Failure()) { try sequencer.producerInstance } - sequencer.releaseIgnoringErrors([Self.key("a")]) - storage.fail(false) - #expect(try sequencer.reserve([Self.key("a")], at: Self.instant).map(\.sequence.rawValue) == ["1"], "the failed release left the reservation") - sequencer.releaseIgnoringErrors([Self.key("a")]) - #expect(try sequencer.reserve([Self.key("a")], at: Self.instant).map(\.sequence.rawValue) == ["2"]) - } - - @Test("Release on an empty storage stores nothing") - func releaseOnEmptyStorageIsANoOp() throws { - let storage = LedgerStorage() - let sequencer = ExchangeEventSequencer(storage: storage) - try sequencer.release([Self.key("a")]) - sequencer.releaseIgnoringErrors([Self.key("a")]) - #expect(storage.data == nil) - #expect(storage.writes == 0) - } - - @Test("A ledger of another schema version is refused, not misread") - func unsupportedSchemaVersionIsRefused() throws { - let storage = LedgerStorage() - storage.seed(#"{"schemaVersion":99,"producerInstance":"1F5C58AA-6EC6-4E79-A682-829A9DEBD3F5","nextSequence":7,"reservations":{}}"#) - let sequencer = ExchangeEventSequencer(storage: storage) - #expect(throws: ExchangeEventSequencer.StateError.unsupportedSchemaVersion(99)) { - try sequencer.reserve([Self.key("a")], at: Self.instant) - } - #expect(throws: ExchangeEventSequencer.StateError.unsupportedSchemaVersion(99)) { try sequencer.producerInstance } - #expect(throws: ExchangeEventSequencer.StateError.unsupportedSchemaVersion(99)) { try sequencer.release([Self.key("a")]) } - #expect(storage.writes == 0) - } - - @Test("A ledger whose sequences are spent refuses a new key but still returns reserved ones") - func exhaustedSequencesAreRefused() throws { - let storage = LedgerStorage() - let reserved = Self.key("a").rawValue - storage.seed( - #"{"schemaVersion":1,"producerInstance":"1F5C58AA-6EC6-4E79-A682-829A9DEBD3F5","nextSequence":18446744073709551615,"# - + #""reservations":{"\#(reserved)":{"sequence":5,"instantMilliseconds":1791023400251,"reservedAtMilliseconds":1791023400251}}}"# - ) - let sequencer = ExchangeEventSequencer(storage: storage) - #expect(try sequencer.producerInstance == UUID(uuidString: "1F5C58AA-6EC6-4E79-A682-829A9DEBD3F5")) - #expect(try sequencer.reserve([Self.key("a")], at: Self.instant).map(\.sequence.rawValue) == ["5"]) - #expect(throws: ExchangeEventSequencer.StateError.sequencesExhausted) { - try sequencer.reserve([Self.key("a"), Self.key("b")], at: Self.instant) - } - #expect(storage.writes == 0, "a refused reservation stores nothing") - } - - @Test("The instant is kept at millisecond precision, the same the lexeme prints") - func instantIsKeptAtMillisecondPrecision() throws { - let sequencer = ExchangeEventSequencer.inMemory() - let inputs = [ - Date(timeIntervalSince1970: 1_791_023_400.2504), - Date(timeIntervalSince1970: 1_791_023_400.2506), - Date(timeIntervalSinceReferenceDate: 0.0015), - Date(timeIntervalSince1970: 1_791_023_400) - ] - let reservations = try sequencer.reserve(inputs.indices.map { Self.key("\($0)") }, at: Self.instant) - #expect(reservations.allSatisfy { ExchangeInstant.millisecondsSinceEpoch($0.instant) == 1_791_023_400_251 }) - for (index, input) in inputs.enumerated() { - let reservation = try sequencer.reserve([Self.key("input-\(index)")], at: input)[0] - #expect(ExchangeInstant.utcLexeme(reservation.instant) == ExchangeInstant.utcLexeme(input)) - #expect(ExchangeInstant.millisecondsSinceEpoch(reservation.instant) == ExchangeInstant.millisecondsSinceEpoch(input)) - #expect(reservation.instant == ExchangeInstant.date(millisecondsSinceEpoch: ExchangeInstant.millisecondsSinceEpoch(input))) - } - } - - @Test("Concurrent reservations from several tasks take unique sequences") - func concurrentReservationsAreUnique() async throws { - let sequencer = ExchangeEventSequencer.inMemory() - let tasks = 8 - let keysPerTask = 50 - let sequences = try await withThrowingTaskGroup(of: [String].self) { group in - for task in 0.. HealthKitConversionSet { + let (ecg, evidence) = try electrocardiogramEvidence(uuid: ordinal, symptomsPresent: symptom != nil) + var symptoms: [HKCategorySample] = [] + var symptomContexts: [HealthKitConversionContext] = [] + if let symptom { + symptoms = [try Self.symptom(uuid: symptom)] + symptomContexts = [try GoldenFixtures.context(sequence: sequence + 100)] + } + return try HealthKitConverter.convertECG( + ecg, + evidence: evidence, + symptoms: symptoms, + context: GoldenFixtures.context(sequence: sequence), + symptomContexts: symptomContexts + ) + } + + /// The sinus-rhythm ECG sample and the validated evidence its voltages would yield, with symptoms present or none. + static func electrocardiogramEvidence( + uuid ordinal: UInt8, + symptomsPresent: Bool + ) throws -> (sample: HKElectrocardiogram, evidence: HealthKitECGEvidence) { let ecg = try StoredSampleFixtures.seriesSample( HKElectrocardiogram.self, sampleType: HKObjectType.electrocardiogramType(), @@ -198,7 +219,7 @@ extension GoldenCase { endDate: GoldenFixtures.sampleStart.addingTimeInterval(30), timeZone: timeZone, classification: .sinusRhythm, - symptomsStatus: symptom == nil ? .none : .present, + symptomsStatus: symptomsPresent ? .present : .none, numberOfVoltageMeasurements: 4, averageHeartRate: 72, samplingFrequency: 500, @@ -215,27 +236,24 @@ extension GoldenCase { HealthKitECGVoltagePoint(timeSinceSampleStart: 0.256, millivolts: 0) ] ) - var symptoms: [HKCategorySample] = [] - var symptomContexts: [HealthKitConversionContext] = [] - if let symptom { - let sample = HKCategorySample( - type: HKCategoryType(.chestTightnessOrPain), - value: HKCategoryValueSeverity.mild.rawValue, - start: GoldenFixtures.sampleStart, - end: GoldenFixtures.sampleStart.addingTimeInterval(30), - device: GoldenFixtures.watch, - metadata: GoldenFixtures.timeZoneMetadata - ) - symptoms = [try StoredSampleFixtures.stored(sample, uuid: symptom, writer: GoldenFixtures.foreignWriter)] - symptomContexts = [try GoldenFixtures.context(sequence: sequence + 100)] - } - return try HealthKitConverter.convertECG( - ecg, - evidence: HealthKitECGEvidence(source: source, waveform: waveform), - symptoms: symptoms, - context: GoldenFixtures.context(sequence: sequence), - symptomContexts: symptomContexts + return (ecg, HealthKitECGEvidence(source: source, waveform: waveform)) + } + + /// A symptom recorded by the watch and written by the foreign application; by default mild chest tightness. + static func symptom( + uuid: UUID, + type: HKCategoryTypeIdentifier = .chestTightnessOrPain, + value: Int = HKCategoryValueSeverity.mild.rawValue + ) throws -> HKCategorySample { + let sample = HKCategorySample( + type: HKCategoryType(type), + value: value, + start: GoldenFixtures.sampleStart, + end: GoldenFixtures.sampleStart.addingTimeInterval(30), + device: GoldenFixtures.watch, + metadata: GoldenFixtures.timeZoneMetadata ) + return try StoredSampleFixtures.stored(sample, uuid: uuid, writer: GoldenFixtures.foreignWriter) } /// A series recorded by the watch, written by the foreign application. diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift index 0cf08110b..bbf16d852 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift @@ -22,7 +22,7 @@ import Testing /// `TEST_RUNNER_GROVE_GOLDEN_OUTPUT_DIR`) names a directory the suite writes every case into, and the files are /// copied into `Resources/Goldens/` afterwards. Writing into the checkout while Xcode runs the tests makes it /// re-resolve the package graph mid-run. -private enum GoldenStore { +enum GoldenStore { struct MissingGolden: Error, CustomStringConvertible { let name: String diff --git a/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift b/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift new file mode 100644 index 000000000..589e3ff11 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift @@ -0,0 +1,114 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import CryptoKit +import Foundation +@testable import GroveFHIRContract +@testable import GroveHealthKitFHIR +import Testing + + +/// One checked-in golden file, its SHA-256 (base64url without padding), and the output revisions it was last +/// changed under. +struct GoldenRevision: Sendable, CustomTestStringConvertible { + let name: String + let digest: String + let assembler: UInt + let healthKit: UInt + + var testDescription: String { name } + + init(_ name: String, digest: String, assembler: UInt, healthKit: UInt) { + self.name = name + self.digest = digest + self.assembler = assembler + self.healthKit = healthKit + } +} + + +/// Guards the output revisions the context fingerprint states. +/// +/// An exact redelivery is byte-identical only while the converter emits the same bytes for the same inputs, so +/// any change that alters a golden must bump `ExchangeGraphAssembler.outputRevision` or +/// `HealthKitAssembly.outputRevision`. This table pins every golden file's digest: a changed golden fails here +/// until its row is updated, and the updated row must carry the bumped revision, which review checks in the +/// diff. A row never names a revision the code has not reached. A new golden adds a row without a bump. +@Suite +struct GoldenOutputRevisionTests { + static let table: [GoldenRevision] = [ + GoldenRevision("blood-pressure-correlation", digest: "Cw-NT44sFRCYAsIii_BZXdS6r0gD2D8dMbV1_DYSuLE", assembler: 1, healthKit: 1), + GoldenRevision("body-mass-user-entered", digest: "SFo9ZdasPxzkAQI2AcW0vlziFfAJyl2L5c-t5eHJdNY", assembler: 1, healthKit: 1), + GoldenRevision("bundled-patient-subject", digest: "DdlaOOPCSIAMV1twtigLxjshiVzTqBaiO_YYaY-QOcA", assembler: 1, healthKit: 1), + GoldenRevision("clinical-document", digest: "1asW-RkPmayr0J1cy__i-SxCb5c64dvfpMYFGkZdsOc", assembler: 1, healthKit: 1), + GoldenRevision("electrocardiogram-symptom-companion", digest: "kr9x4zg2fLjcx8pXVU1zrNAkyOeXZDrOoDLW3QPA188", assembler: 1, healthKit: 1), + GoldenRevision("electrocardiogram-with-symptom", digest: "9l2JtyHoAElz12UR_N0uGxnZo0YLw4X1vH-asSwgPfc", assembler: 1, healthKit: 1), + GoldenRevision("electrocardiogram", digest: "4O8qSuiYKdJHCH6i1nQLwaj9Wj_WTXNJQSvGaTa4TZc", assembler: 1, healthKit: 1), + GoldenRevision("gateway-application-role", digest: "1CfpIPrpl4EoRrQU9eimlM8i2ArNVdpbTk3mIAsBgXs", assembler: 1, healthKit: 1), + GoldenRevision("gateway-role", digest: "JtaVascxlW4cJfq-aH6p2JDab9u-YfQiaSFtwvhiMFY", assembler: 1, healthKit: 1), + GoldenRevision("heart-rate-device-without-unit-token", digest: "gKIE0MA3n8uoEIiPTWI-TJOBDAD1osZVz6C0sWLibk8", assembler: 1, healthKit: 1), + GoldenRevision("heart-rate-interval", digest: "D4QTr9s6IiDjDLGr6Gm41p4QjU8Go6oXajrRteRhwaU", assembler: 1, healthKit: 1), + GoldenRevision("heart-rate-minimal", digest: "iYrgj5FAgmujztGZvH5fPK2gu0rzDPJF0Z3CSWallZ0", assembler: 1, healthKit: 1), + GoldenRevision("heart-rate-motion-context", digest: "2eNSC6noLNjTP_8f0QwoBCIPwoBAIBlr-gOiRTG0lpw", assembler: 1, healthKit: 1), + GoldenRevision("heart-rate-no-time-zone", digest: "7tJhGKGIbj6MVPQ2P4cNI0KN-MLI2MBUk763HC5kkfk", assembler: 1, healthKit: 1), + GoldenRevision("heart-rate-recording-device", digest: "IIHNioDM2ZkeqNYCg_8f0HPuPC3b-pPdHziLJEm2j3U", assembler: 1, healthKit: 1), + GoldenRevision("heart-rate-study", digest: "sftiHrOuakPAfN5bjto9VoPE7_RpZ1k3YcGDKEqkFDI", assembler: 1, healthKit: 1), + GoldenRevision("heartbeat-series", digest: "lkN3HRrrJDbWJil2kZg3LKKgmRGyzmEVWgJEugZroEM", assembler: 1, healthKit: 1), + GoldenRevision("insulin-delivery-bolus", digest: "fCw3-HgNHCW_r1bQ8bY5WiGz52iekzNbJ0-AKZp59yc", assembler: 1, healthKit: 1), + GoldenRevision("native-identifier-disclosure", digest: "FUSVYtEc61Y5479e6WSJYoDPoJz4x5BRgpp61H0DP0I", assembler: 1, healthKit: 1), + GoldenRevision("outlines", digest: "dcGlAzsmhgyWChE4Tc78Y_kC0ZQmp5IJ-NKab8fLrZA", assembler: 1, healthKit: 1), + GoldenRevision("repository-ids-on-every-node", digest: "wnO8sPt82cYYd4m50n4tycbEXWdgvNRlKjQItQI6n4Y", assembler: 1, healthKit: 1), + GoldenRevision("retraction-blood-pressure", digest: "x4muVgyjqh8AfgVGhaS55MeMVmxJ58UR0hsghhedkEA", assembler: 1, healthKit: 1), + GoldenRevision("retraction-electrocardiogram", digest: "JJIp4J2S4Vr0CX-d1fi3IqAmyNzuzSz4fyrF-gbrkgM", assembler: 1, healthKit: 1), + GoldenRevision("retraction-heart-rate-native-identifier", digest: "2nx6odq_wixvjnzRfksJPRgR_UcNs4LkE2l3El_38r4", assembler: 1, healthKit: 1), + GoldenRevision("retraction-heart-rate", digest: "Bol04wjtd82Dt8GlmFMS84fxEQ6DgPpRsdN-Zd5OA8g", assembler: 1, healthKit: 1), + GoldenRevision("retraction-workout", digest: "XsaDOMjgcyxDx-jQFZB2bLIcotexSJkELvAPeLOc7Oo", assembler: 1, healthKit: 1), + GoldenRevision("sleep-analysis", digest: "iNlzbKzQmvuuwSYNtP01iBO0aUf7I6bcRiv7FtZsWx8", assembler: 1, healthKit: 1), + GoldenRevision("state-of-mind", digest: "tKLQnzIzG1NWFOB2Tlfy4wcZ30_0JzFq4iPyzcLUFXc", assembler: 1, healthKit: 1), + GoldenRevision("step-count-period", digest: "EGtl-T8Y_4ZYOsQrwTOwooimTqzOPzOizTeh_1xUyuI", assembler: 1, healthKit: 1), + GoldenRevision("sync-identity", digest: "AVB5QYfWDT4HHvzqxJ7SMeUMLU4miCMWO0m8tjG6Vyg", assembler: 1, healthKit: 1), + GoldenRevision("two-study-enrollments", digest: "6xtFx6cUROnfra3ZXo_ItI81yhmfSSCsXe9nlJb039A", assembler: 1, healthKit: 1), + GoldenRevision("udi-disclosure", digest: "U6I4SPk8ZMG1qYnzUpuuXmtZmPJ9bwdCinbmH515Bgw", assembler: 1, healthKit: 1), + GoldenRevision("workout-route", digest: "qcXsPsBE21qllakPbqcY5JziHqKDqq_Kr5wPgr8ppks", assembler: 1, healthKit: 1), + GoldenRevision("workout-session", digest: "1JlAdaXFilr2KXrYdxEvZXAGjMUaSxFaJfiPpZuvGlE", assembler: 1, healthKit: 1), + GoldenRevision("writer-blank-name-with-sync-identity", digest: "eGHwwHdaM8H_QqW2kRQqNcXBj-309dPxpqy3gkXnKNU", assembler: 1, healthKit: 1), + GoldenRevision("writer-device-classification-without-recording-device", digest: "SnLRcZTmF2g6qdUj-M4UiX6yZGYMavPfLDzJ_3hQPeY", assembler: 1, healthKit: 1), + GoldenRevision("writer-device-classification", digest: "yZStG8Raudsb--4jeSQkKpkr1ZctGAOJKy81JTmYNMs", assembler: 1, healthKit: 1), + GoldenRevision("writer-foreign-application", digest: "SaD46SDNVFB6NPQJmIBglAQpwczYwAKlQvSlLl8-d24", assembler: 1, healthKit: 1), + GoldenRevision("writer-host-equals-converter-host", digest: "fGxbULDNVld5Ke8SXJEiEaHwi_W-3p2KTFpG7i6jQQs", assembler: 1, healthKit: 1), + GoldenRevision("writer-self-build-equals-revision", digest: "eqwa6qOx48BRIZuR-XapwsKmhNC5G_IaKGtHU_drvVc", assembler: 1, healthKit: 1), + GoldenRevision("writer-self-older-build", digest: "q59J2fyLBpYqXMqk2gBm1xqXtOmgW3uCHWFMaeQgF5Q", assembler: 1, healthKit: 1), + GoldenRevision("writer-self-token-identical", digest: "jAlS6dY8iVYxVegEVLk8WC2TOmLam51chxDE7WuWf5k", assembler: 1, healthKit: 1), + GoldenRevision("writer-without-version", digest: "6cAe98cV6GLI-79ir2LvcG0yd9lT0aHnoz60tvoiW_A", assembler: 1, healthKit: 1) + ] + + @Test("G17: every golden file has a row, and every row names an existing golden") + func everyGoldenHasARow() { + let rows = Set(Self.table.map(\.name)) + #expect(rows.count == Self.table.count, "a golden is named twice") + let checkedIn = GoldenStore.checkedInNames + #expect(checkedIn.subtracting(rows).isEmpty, "goldens without a revision row: \(checkedIn.subtracting(rows).sorted())") + let stale = rows.subtracting(checkedIn).subtracting(GoldenCase.unavailableHere) + #expect(stale.isEmpty, "rows without a golden: \(stale.sorted())") + } + + @Test("G17: a golden's bytes match its row, whose revisions the code has reached", arguments: GoldenOutputRevisionTests.table) + func goldenMatchesItsRevision(_ row: GoldenRevision) throws { + guard !GoldenCase.unavailableHere.contains(row.name) else { + return + } + let digest = Data(SHA256.hash(data: try GoldenStore.data(named: row.name))).base64URLEncodedStringWithoutPadding + #expect(digest == row.digest, "\(row.name) changed: update its row with the bumped output revision") + #expect(row.assembler <= ExchangeGraphAssembler.outputRevision) + #expect(row.healthKit <= HealthKitAssembly.outputRevision) + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitConverter+TestSeams.swift b/Tests/GroveHealthKitFHIRTests/HealthKitConverter+TestSeams.swift index 647969e80..ad851400c 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitConverter+TestSeams.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitConverter+TestSeams.swift @@ -55,7 +55,7 @@ extension HealthKitConverter { evidence: evidence, symptoms: symptoms, request: .init(context: context), - symptomRequests: symptomContexts.map { .init(context: $0) } + symptomRequests: .positional(symptomContexts.map { .init(context: $0) }) ) } diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFingerprintTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFingerprintTests.swift new file mode 100644 index 000000000..27973d8ec --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFingerprintTests.swift @@ -0,0 +1,126 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import CryptoKit +import Foundation +@testable import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit +import Testing + + +/// A resolver whose only distinguishing feature is that the deployment supplied it. +private struct NoRecordingDevice: RecordingDeviceResolver { + func recordingDevice(for device: HKDevice) -> RecordingDevice? { + nil + } +} + + +/// The context fingerprint: everything that shapes a graph but is not frozen with its event. +@Suite +struct HealthKitFHIRExporterFingerprintTests { + private typealias Fixtures = ExporterFixtures + private typealias Configure = (inout HealthKitFHIRExporter.Options) -> Void + + private static let key = SymmetricKey(data: Data(repeating: 0x42, count: 32)) + + /// Every option perturbation the fingerprint must tell apart from the defaults and from each other. + @available(*, deprecated, message: "Names the transitional legacy Bundle.id case") + private static func optionPerturbations() -> [(String, Configure)] { + let gateway = ApplicationDevice.test(name: "Cuff Companion", bundleIdentifier: "com.example.cuff", version: "3.1", build: "9") + let system = GoldenFixtures.nativeIdentifierSystem + let typeSystem: IdentifierSystem = "https://study.example.org/fhir/CodeSystem/identifier-type" + let otherSystem: IdentifierSystem = "https://study.example.org/fhir/CodeSystem/other-type" + return [ + ("route", { $0.route = .authorized }), + ("legacyBundleID", { $0.legacyBundleID = .healthKitUUID }), + ("writer application", { $0.writer = .application }), + ("writer device", { $0.writer = .device }), + ("writer omit", { $0.writer = .omit }), + ("recordingDevice omit", { $0.recordingDevice = .omit }), + ("recordingDevice custom", { $0.recordingDevice = .custom(NoRecordingDevice()) }), + ("role gatewayForOwnWrites", { $0.role = .gatewayForOwnWrites }), + ("role gateway", { $0.role = .gateway }), + ("role gatewayApplication", { $0.role = .gatewayApplication(gateway) }), + ("gateway name", { $0.role = .gatewayApplication(.test(name: "Other", bundleIdentifier: "com.example.cuff", version: "3.1", build: "9")) }), + ("gateway bundle", { $0.role = .gatewayApplication(.test(name: "Cuff Companion", bundleIdentifier: "com.example.x", version: "3.1", build: "9")) }), + ("gateway version", { $0.role = .gatewayApplication(.test(name: "Cuff Companion", bundleIdentifier: "com.example.cuff", version: "3.2", build: "9")) }), + ("gateway build", { $0.role = .gatewayApplication(.test(name: "Cuff Companion", bundleIdentifier: "com.example.cuff", version: "3.1")) }), + ("nativeIdentifier", { $0.nativeIdentifier = .authorized(system: system) }), + ("nativeIdentifier system", { $0.nativeIdentifier = .authorized(system: "https://study.example.org/fhir/NamingSystem/other") }), + ("type", { $0.nativeIdentifier = .authorized(system: system, type: try? GovernedSourceIdentifierType(system: typeSystem, code: "store")) }), + ("type system", { $0.nativeIdentifier = .authorized(system: system, type: try? GovernedSourceIdentifierType(system: otherSystem, code: "store")) }), + ("type code", { $0.nativeIdentifier = .authorized(system: system, type: try? GovernedSourceIdentifierType(system: typeSystem, code: "record")) }), + ("type display", { + $0.nativeIdentifier = .authorized(system: system, type: try? GovernedSourceIdentifierType(system: typeSystem, code: "store", display: "Store")) + }), + ("udi", { $0.udi = .authorized }) + ] + } + + @Test("G3: every option, the subject, the repository and identity scopes and each output revision version the event") + @available(*, deprecated, message: "Names the transitional legacy Bundle.id case") + func everyContextInputVersionsTheEvent() throws { + let sequencer = ExchangeEventSequencer.inMemory() + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(1), device: GoldenFixtures.watch, writer: GoldenFixtures.foreignWriter) + let base = try Fixtures.producer(sequencer: sequencer) + var exporters: [(String, HealthKitFHIRExporter)] = try Self.optionPerturbations().map { name, configure in + (name, try Fixtures.exporter(base, configure)) + } + let systems = Fixtures.base.identityScope.systems + exporters += [ + ("subject", try Fixtures.exporter(try Fixtures.producer(subject: .logical(.test(.patient, "other")), sequencer: sequencer))), + ("bundled subject", try Fixtures.exporter(try Fixtures.producer(subject: .bundled(.test(.patient, "example"), .init()), sequencer: sequencer))), + ("repository scope", try Fixtures.exporter(base, repositoryScope: .test(.device, "secondary"))), + ("epoch", try Fixtures.exporter(try Fixtures.producer( + identityScope: OpaqueIdentityScope(systems: systems, keyID: "test", epoch: EventSequence(2), key: Self.key), + sequencer: sequencer + ))), + ("key", try Fixtures.exporter(try Fixtures.producer( + identityScope: OpaqueIdentityScope(systems: systems, keyID: "test", epoch: EventSequence(1), key: SymmetricKey(data: Data(repeating: 7, count: 32))), + sequencer: sequencer + ))), + ("assembler revision", try Fixtures.exporter(base, revisions: .init(assembler: ExchangeGraphAssembler.outputRevision + 1, healthKit: HealthKitAssembly.outputRevision))), + ("adapter revision", try Fixtures.exporter(base, revisions: .init(assembler: ExchangeGraphAssembler.outputRevision, healthKit: HealthKitAssembly.outputRevision + 1))) + ] + let (original, _) = try Fixtures.collect(try Fixtures.exporter(base), samples: [sample]) + let (unchanged, _) = try Fixtures.collect(try Fixtures.exporter(base), samples: [sample]) + #expect(unchanged[0].event == original[0].event, "an equal context reuses the reservation") + var sequences = [try #require(original[0].sequence)] + for (name, exporter) in exporters { + let (exports, _) = try Fixtures.collect(exporter, samples: [sample]) + let sequence = try #require(exports[0].sequence, "\(name): \(exports[0].outcome)") + #expect(!sequences.contains(sequence), "\(name) reused an event") + sequences.append(sequence) + } + } + + @Test("G3b: the fingerprint covers every stored option") + func fingerprintCoversEveryOption() { + let options = HealthKitFHIRExporter.Options() + let stored = Mirror(reflecting: options).children.compactMap(\.label) + #expect(!stored.isEmpty) + #expect(options.fingerprintParts.map(\.property) == stored) + } + + @Test("The ledger fingerprint of an identity scope is keyed and reveals nothing about the key") + func ledgerFingerprintIsKeyed() throws { + let scope = Fixtures.base.identityScope + let again = try OpaqueIdentityScope(systems: scope.systems, keyID: scope.keyID, epoch: scope.epoch, key: Self.key) + let rekeyed = try OpaqueIdentityScope(systems: scope.systems, keyID: scope.keyID, epoch: scope.epoch, key: SymmetricKey(data: Data(repeating: 7, count: 32))) + #expect(scope.ledgerFingerprint == again.ledgerFingerprint) + #expect(scope.ledgerFingerprint != rekeyed.ledgerFingerprint) + #expect(scope.ledgerFingerprint.utf8.count == 43) + #expect(!scope.ledgerFingerprint.contains(Data(repeating: 0x42, count: 32).base64EncodedString())) + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFixtures.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFixtures.swift new file mode 100644 index 000000000..0fcd6acd0 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFixtures.swift @@ -0,0 +1,174 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +@testable import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit + + +/// Counts the ledger transactions and writes an exporter makes over an in-memory ledger. +final class LedgerCountingStorage: ExchangeEventSequencer.Storage, @unchecked Sendable { // The counts are guarded by `lock`. + private struct Counting: ExchangeEventSequencer.Transaction { + let base: any ExchangeEventSequencer.Transaction + let storage: LedgerCountingStorage + + func read(_ key: String) throws -> Data? { + try base.read(key) + } + + func write(_ value: Data, for key: String) throws { + storage.countWrite() + try base.write(value, for: key) + } + + func remove(_ key: String) throws { + storage.countWrite() + try base.remove(key) + } + + func keys(prefixedBy prefix: String) throws -> [String] { + try base.keys(prefixedBy: prefix) + } + } + + let base = ExchangeEventSequencer.InMemoryStorage() + private let lock = NSLock() + private var transactions = 0 + private var writes = 0 + + /// Transactions and writes (removals included) since the last call, which starts a new tally. + func take() -> (transactions: Int, writes: Int) { + lock.lock() + defer { + lock.unlock() + } + defer { + (transactions, writes) = (0, 0) + } + return (transactions, writes) + } + + func transaction(_ body: (any ExchangeEventSequencer.Transaction) throws -> R) throws -> R { + lock.lock() + transactions += 1 + lock.unlock() + return try base.transaction { try body(Counting(base: $0, storage: self)) } + } + + /// Whether the ledger holds a reservation for `key`. + func holdsReservation(for key: ExchangeEventKey) throws -> Bool { + try base.transaction { try $0.read(LedgerKey.event(key)) } != nil + } + + private func countWrite() { + lock.lock() + defer { + lock.unlock() + } + writes += 1 + } +} + + +/// Producers, exporters and records the exporter tests share. +enum ExporterFixtures { + static let base = ExchangeEventContext.test() + + static func producer( + identityScope: OpaqueIdentityScope = base.identityScope, + subject: Subject = base.subject, + application: ApplicationDevice = base.application, + host: HostDevice = base.host, + studies: [StudyEnrollment] = [], + sequencer: ExchangeEventSequencer + ) throws -> ExchangeProducer { + try ExchangeProducer( + identityScope: identityScope, + subject: subject, + application: application, + host: host, + studies: studies, + sequencer: sequencer + ) + } + + static func exporter( + _ producer: ExchangeProducer, + repositoryScope: BusinessIdentifier = base.repositoryScope, + revisions: HealthKitFHIRExporter.OutputRevisions = .current, + _ configure: (inout HealthKitFHIRExporter.Options) -> Void = { _ in } + ) throws -> HealthKitFHIRExporter { + var options = HealthKitFHIRExporter.Options() + configure(&options) + return try HealthKitFHIRExporter(producer: producer, repositoryScope: repositoryScope, options: options, outputRevisions: revisions) + } + + static func exporter( + sequencer: ExchangeEventSequencer = .inMemory(), + _ configure: (inout HealthKitFHIRExporter.Options) -> Void = { _ in } + ) throws -> HealthKitFHIRExporter { + try exporter(producer(sequencer: sequencer), configure) + } + + /// Every export of one call, and its receipt. + static func collect( + _ exporter: HealthKitFHIRExporter, + _ inputs: [HealthKitFHIRExporter.Input], + at instant: Date = GoldenFixtures.conversionInstant + ) throws -> (exports: [HealthKitFHIRExporter.Export], receipt: HealthKitFHIRExporter.Receipt) { + var exports: [HealthKitFHIRExporter.Export] = [] + let receipt = try exporter.export(inputs: inputs, at: instant) { exports.append($0) } + return (exports, receipt) + } + + static func collect( + _ exporter: HealthKitFHIRExporter, + samples: [HKSample], + at instant: Date = GoldenFixtures.conversionInstant + ) throws -> (exports: [HealthKitFHIRExporter.Export], receipt: HealthKitFHIRExporter.Receipt) { + try collect(exporter, samples.map { .record(.sample($0)) }, at: instant) + } + + static func retract( + _ exporter: HealthKitFHIRExporter, + _ deletions: [HealthKitFHIRExporter.Deletion], + at instant: Date = GoldenFixtures.conversionInstant + ) throws -> (exports: [HealthKitFHIRExporter.Export], receipt: HealthKitFHIRExporter.Receipt) { + var exports: [HealthKitFHIRExporter.Export] = [] + let receipt = try exporter.retract(deletions, at: instant) { exports.append($0) } + return (exports, receipt) + } + + /// An ECG with prebuilt evidence and its correlated symptoms, through the exporter's internal seam. + static func electrocardiogram(uuid ordinal: UInt8, symptoms: [HKCategorySample]) throws -> HealthKitFHIRExporter.Input { + let (ecg, evidence) = try GoldenCase.electrocardiogramEvidence(uuid: ordinal, symptomsPresent: !symptoms.isEmpty) + return .electrocardiogramEvidence(ecg, evidence: evidence, symptoms: symptoms) + } + + static func deletion(_ ordinal: UInt8, deletedAfter: Date? = nil, detectedAt: Date = GoldenFixtures.conversionInstant) -> HealthKitFHIRExporter.Deletion { + HealthKitFHIRExporter.Deletion(uuid: GoldenFixtures.uuid(ordinal), sourceType: .heartRate, deletedAfter: deletedAfter, detectedAt: detectedAt) + } +} + + +extension HealthKitFHIRExporter.Export { + /// The graph's event identifier. + var event: ExchangeEventIdentifier? { + graph?.eventIdentifier + } + + /// The graph's event sequence. + var sequence: String? { + graph?.eventIdentifier.sequence.rawValue + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterLedgerTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterLedgerTests.swift new file mode 100644 index 000000000..9667e65e7 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterLedgerTests.swift @@ -0,0 +1,299 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +@testable import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit +import ModelsR4 +import Testing + + +/// The exporter's use of the ledger: frozen facts, holds, receipts, record-level fingerprints, ECG pairing. +@Suite +struct HealthKitFHIRExporterLedgerTests { + private typealias Fixtures = ExporterFixtures + + /// A category type the catalog does not register, where this OS knows one (bleeding after menopause, OS 27). + static var unregisteredCategoryType: HKCategoryTypeIdentifier? { + let identifier = HKCategoryTypeIdentifier(rawValue: "HKCategoryTypeIdentifierBleedingAfterMenopause") + return HKObjectType.categoryType(forIdentifier: identifier) == nil ? nil : identifier + } + + private static func study(revision: String) throws -> StudyEnrollment { + try StudyEnrollment( + study: .test(.researchStudy, "s1"), + protocolURL: FHIRPrimitive(Canonical(stringLiteral: "https://study.example.org/PlanDefinition/s1")), + protocolVersion: revision, + enrollment: .test(.researchSubject, "enrollment-s1") + ) + } + + /// The application versions every Device of `graph` states. + private static func deviceVersions(_ graph: ExchangeGraph?) -> Set { + let devices = graph?.bundle.entry?.compactMap { $0.resource?.get(if: Device.self) } ?? [] + return Set(devices.flatMap { $0.version ?? [] }.compactMap { $0.value.value?.string }) + } + + /// One heart rate, one ECG with a symptom, and one retraction, under `producer`. + private static func deliver( + under producer: ExchangeProducer + ) throws -> (exports: [HealthKitFHIRExporter.Export], receipts: [HealthKitFHIRExporter.Receipt]) { + let exporter = try Fixtures.exporter(producer) + let records: [HealthKitFHIRExporter.Input] = [ + .record(.sample(try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(1)))), + try Fixtures.electrocardiogram(uuid: 2, symptoms: [try GoldenCase.symptom(uuid: GoldenFixtures.uuid(3))]) + ] + let (exports, receipt) = try Fixtures.collect(exporter, records) + let (retractions, retractionReceipt) = try Fixtures.retract(exporter, [Fixtures.deletion(4, deletedAfter: GoldenFixtures.sampleStart)]) + return (exports + retractions, [receipt, retractionReceipt]) + } + + @Test("G2: a redelivery before release is byte-identical across app, OS and study changes; after release it is new") + func redeliveryIsByteIdenticalAcrossFactChanges() throws { + let sequencer = ExchangeEventSequencer.inMemory() + let original = try Fixtures.producer( + application: .test(name: "Grove Test", bundleIdentifier: "org.grovealliance.test", version: "1.0", build: "100"), + host: try HostDevice(operatingSystemVersion: "26.0", modelNumber: "iPhone17,1"), + studies: [], + sequencer: sequencer + ) + let first = try Self.deliver(under: original) + try #require(first.exports.count == 4) + var receipts = first.receipts + // App 1.0 (100) to 1.1 (110), OS 26.0 to 27.0, studies [] to [s1 rev 1], then [s1 rev 1] to [s1 rev 2]. + let updated = try ["1", "2"].map { revision in + try Fixtures.producer( + application: .test(name: "Grove Test", bundleIdentifier: "org.grovealliance.test", version: "1.1", build: "110"), + host: try HostDevice(operatingSystemVersion: "27.0", modelNumber: "iPhone17,1"), + studies: [try Self.study(revision: revision)], + sequencer: sequencer + ) + } + for producer in updated { + let again = try Self.deliver(under: producer) + #expect(again.exports.map(\.graph?.json) == first.exports.map(\.graph?.json)) + #expect(again.exports.map(\.event) == first.exports.map(\.event)) + receipts += again.receipts + } + #expect(Self.deviceVersions(first.exports[0].graph).contains("1.0")) + receipts.forEach { $0.release() } + let renewed = try Self.deliver(under: try #require(updated.last)) + for (renewedExport, firstExport) in zip(renewed.exports, first.exports) { + #expect(renewedExport.event != firstExport.event) + #expect(renewedExport.graph?.json != firstExport.graph?.json) + } + #expect(Self.deviceVersions(renewed.exports[0].graph).contains("1.1")) + #expect(!Self.deviceVersions(renewed.exports[0].graph).contains("1.0")) + } + + @Test("G18: the first delivery and a redelivery through a fresh process produce byte-equal graphs") + func redeliveryThroughAFreshProcessIsByteEqual() throws { + let storage = ExchangeEventSequencer.InMemoryStorage() + let studies = [try Self.study(revision: "1"), StudyEnrollment.test("s2")] + let first = try Self.deliver(under: try Fixtures.producer(studies: studies, sequencer: ExchangeEventSequencer(storage: storage, holds: HoldRegistry()))) + let restarted = ExchangeEventSequencer(storage: storage, holds: HoldRegistry()) + let again = try Self.deliver(under: try Fixtures.producer(studies: [], sequencer: restarted)) + #expect(again.exports.map(\.graph?.json) == first.exports.map(\.graph?.json)) + } + + @Test("G8: a call that throws in receive leaves its reservations; the redelivery reuses them and its release removes them") + func throwingDeliveryLapses() throws { + struct Stop: Error {} + let storage = LedgerCountingStorage() + let exporter = try Fixtures.exporter(sequencer: ExchangeEventSequencer(storage: storage)) + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(5)) + let key = try #require(ExchangeEventKey.active(sample)) + #expect(throws: Stop.self) { + try exporter.export([sample]) { _ in throw Stop() } + } + #expect(try storage.holdsReservation(for: key)) + let (again, receipt) = try Fixtures.collect(exporter, samples: [sample]) + #expect(again[0].sequence == "1") + receipt.release() + #expect(try !storage.holdsReservation(for: key)) + } + + @Test("G9: overlapping calls keep a shared event until the last one finishes; double releases count once") + func overlappingReceipts() throws { + let storage = LedgerCountingStorage() + let exporter = try Fixtures.exporter(sequencer: ExchangeEventSequencer(storage: storage)) + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(6)) + let key = try #require(ExchangeEventKey.active(sample)) + let (live, liveReceipt) = try Fixtures.collect(exporter, samples: [sample]) + var bulkReceipt: HealthKitFHIRExporter.Receipt? + do { + let bulk = try Fixtures.collect(exporter, samples: [sample]) + #expect(live[0].graph?.json == bulk.exports[0].graph?.json) + bulkReceipt = bulk.receipt + } + // The first release, twice and through a second reference, marks the event; the slower call still holds it. + let alias = liveReceipt + liveReceipt.release() + alias.release() + liveReceipt.release() + #expect(try storage.holdsReservation(for: key)) + let (redelivery, redeliveryReceipt) = try Fixtures.collect(exporter, samples: [sample]) + #expect(redelivery[0].graph?.json == live[0].graph?.json, "a redelivery by the slower call is an exact retry") + redeliveryReceipt.release() + #expect(try storage.holdsReservation(for: key)) + // A lost compare-exchange: the remaining holder is dropped unreleased, and as the last one it removes the event. + #expect(bulkReceipt != nil) + bulkReceipt = nil + #expect(try !storage.holdsReservation(for: key)) + } + + @Test("G9e: a refused ECG companion keeps the standalone symptom's event in the same call") + func refusedCompanionKeepsTheStandaloneSymptom() throws { + let storage = LedgerCountingStorage() + let exporter = try Fixtures.exporter(sequencer: ExchangeEventSequencer(storage: storage)) + let symptom = try GoldenCase.symptom(uuid: GoldenFixtures.uuid(0x71)) + // Symptoms present but the evidence says none: the ECG is refused, its companion with it. + let (ecg, evidence) = try GoldenCase.electrocardiogramEvidence(uuid: 0x70, symptomsPresent: false) + let (first, receipt) = try Fixtures.collect(exporter, [ + .electrocardiogramEvidence(ecg, evidence: evidence, symptoms: [symptom]), + .record(.sample(symptom)) + ]) + guard case .refused = first[0].outcome else { + Issue.record("expected the ECG to be refused, got \(first[0].outcome)") + return + } + let standalone = try #require(first[1].graph) + let (again, againReceipt) = try Fixtures.collect(exporter, samples: [symptom]) + #expect(again[0].graph?.json == standalone.json, "the symptom's event survived the refusal") + let key = try #require(ExchangeEventKey.active(symptom)) + receipt.release() + #expect(try storage.holdsReservation(for: key), "the redelivery still holds it") + againReceipt.release() + #expect(try !storage.holdsReservation(for: key)) + } + + @Test("G10: an export and its release take one ledger transaction each; an empty receipt and a reuse write nothing") + func transactionBudget() throws { + let storage = LedgerCountingStorage() + let exporter = try Fixtures.exporter(sequencer: ExchangeEventSequencer(storage: storage)) + let samples = try (7...9).map { try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid($0)) } + let (_, receipt) = try Fixtures.collect(exporter, samples: samples) + #expect(storage.take().transactions == 1) + let (_, again) = try Fixtures.collect(exporter, samples: samples) + #expect(storage.take() == (transactions: 1, writes: 0)) + receipt.release() + again.release() + #expect(storage.take().transactions == 1) + let (_, empty) = try Fixtures.collect(exporter, samples: []) + empty.release() + #expect(storage.take().transactions == 0) + } + + @Test("G4: a changed symptom set or changed deletion bounds is a new event; two bounds in one call are two events") + func recordPartsVersionTheEvent() throws { + let exporter = try Fixtures.exporter() + let one = try GoldenCase.symptom(uuid: GoldenFixtures.uuid(0x81)) + let two = try GoldenCase.symptom(uuid: GoldenFixtures.uuid(0x82), type: .fatigue) + let (single, _) = try Fixtures.collect(exporter, [try Fixtures.electrocardiogram(uuid: 0x80, symptoms: [one])]) + let (same, _) = try Fixtures.collect(exporter, [try Fixtures.electrocardiogram(uuid: 0x80, symptoms: [one])]) + let (pair, _) = try Fixtures.collect(exporter, [try Fixtures.electrocardiogram(uuid: 0x80, symptoms: [two, one])]) + #expect(same[0].event == single[0].event) + #expect(pair[0].event != single[0].event) + #expect(pair.first { $0.source.uuid == one.uuid }?.event == single[1].event, "the unchanged symptom keeps its event") + let before = try Fixtures.retract(exporter, [Fixtures.deletion(0x83, deletedAfter: GoldenFixtures.sampleStart)]) + let after = try Fixtures.retract(exporter, [Fixtures.deletion(0x83, deletedAfter: GoldenFixtures.sampleStart + 1)]) + #expect(before.exports[0].event != after.exports[0].event) + let both = try Fixtures.retract(exporter, [ + Fixtures.deletion(0x84, deletedAfter: GoldenFixtures.sampleStart), + Fixtures.deletion(0x84, deletedAfter: nil), + Fixtures.deletion(0x84, deletedAfter: GoldenFixtures.sampleStart) + ]) + #expect(both.exports[0].event != both.exports[1].event) + #expect(both.exports[0].event == both.exports[2].event) + #expect(both.exports[0].graph?.json != both.exports[1].graph?.json) + } + + @Test("G11: a released retraction forgets the deleted record's active reservation; an unreleased one forgets nothing") + func retractionForgetsTheActiveKey() throws { + let storage = LedgerCountingStorage() + let exporter = try Fixtures.exporter(sequencer: ExchangeEventSequencer(storage: storage)) + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0x90)) + let key = try #require(ExchangeEventKey.active(sample)) + let (first, _) = try Fixtures.collect(exporter, samples: [sample]) + _ = try Fixtures.retract(exporter, [Fixtures.deletion(0x90)]) + #expect(try storage.holdsReservation(for: key), "a dropped retraction receipt forgets nothing") + let (kept, _) = try Fixtures.collect(exporter, samples: [sample]) + #expect(kept[0].event == first[0].event) + let retraction = try Fixtures.retract(exporter, [Fixtures.deletion(0x90)]) + retraction.receipt.release() + #expect(try !storage.holdsReservation(for: key)) + let (renewed, _) = try Fixtures.collect(exporter, samples: [sample]) + #expect(renewed[0].event != first[0].event) + } + + @Test("E1: each ECG symptom maps to its own reservation by key, never by position") + func symptomsPairByKey() throws { + let exporter = try Fixtures.exporter() + let first = try GoldenCase.symptom(uuid: GoldenFixtures.uuid(0xA1)) + let last = try GoldenCase.symptom(uuid: GoldenFixtures.uuid(0xA3), type: .fatigue) + let (paired, _) = try Fixtures.collect(exporter, [try Fixtures.electrocardiogram(uuid: 0xA4, symptoms: [last, first])]) + let (standalone, _) = try Fixtures.collect(exporter, samples: [first, last]) + try #require(paired.count == 3) + #expect(paired.first { $0.source.uuid == first.uuid }?.graph?.json == standalone[0].graph?.json) + #expect(paired.first { $0.source.uuid == last.uuid }?.graph?.json == standalone[1].graph?.json) + } + + @Test( + "E1: an unregistered symptom between two registered ones is refused as unsupported, the others keep their own requests", + .enabled(if: HealthKitFHIRExporterLedgerTests.unregisteredCategoryType != nil, "no unregistered category type exists before OS 27") + ) + func unregisteredSymptomIsRefusedAsSuch() throws { + let exporter = try Fixtures.exporter() + let type = try #require(Self.unregisteredCategoryType) + let first = try GoldenCase.symptom(uuid: GoldenFixtures.uuid(0xA1)) + let unregistered = try GoldenCase.symptom(uuid: GoldenFixtures.uuid(0xA2), type: type, value: 1) + let last = try GoldenCase.symptom(uuid: GoldenFixtures.uuid(0xA3), type: .fatigue) + #expect(HealthKitSourceType(unregistered) == nil) + let input = try Fixtures.electrocardiogram(uuid: 0xA0, symptoms: [first, unregistered, last]) + let plan = HealthKitFHIRExporter.Plan(input, context: exporter.context) + #expect(plan.symptoms.map { $0?.key } == [ExchangeEventKey.active(first), nil, ExchangeEventKey.active(last)]) + let (exports, _) = try Fixtures.collect(exporter, [input]) + guard case .refused(let reason) = exports[0].outcome else { + Issue.record("expected a refusal, got \(exports[0].outcome)") + return + } + #expect(reason == .ecgEvidence(.unsupportedSymptomType(type.rawValue))) + } + + @Test("E2: an ECG through the records path takes one reserve, mints its symptoms' events, and redelivers byte-identically") + func electrocardiogramThroughTheRecordsPath() throws { + let storage = LedgerCountingStorage() + let exporter = try Fixtures.exporter(sequencer: ExchangeEventSequencer(storage: storage)) + let symptom = try GoldenCase.symptom(uuid: GoldenFixtures.uuid(0xB1)) + let input = try Fixtures.electrocardiogram(uuid: 0xB0, symptoms: [symptom]) + let (first, receipt) = try Fixtures.collect(exporter, [input]) + #expect(storage.take().transactions == 1) + try #require(first.count == 2) + #expect(Set(first.compactMap(\.sequence)) == ["1", "2"]) + #expect(first[1].source.uuid == symptom.uuid) + let (again, _) = try Fixtures.collect(exporter, [input]) + #expect(again.map(\.graph?.json) == first.map(\.graph?.json)) + // A refused record holds its keys until the receipt is released. + let (refusedECG, refusedEvidence) = try GoldenCase.electrocardiogramEvidence(uuid: 0xB2, symptomsPresent: false) + let refusedKey = try #require(ExchangeEventKey.active(refusedECG)) + let (refused, refusedReceipt) = try Fixtures.collect(exporter, [.electrocardiogramEvidence(refusedECG, evidence: refusedEvidence, symptoms: [symptom])]) + guard case .refused = refused[0].outcome else { + Issue.record("expected a refusal, got \(refused[0].outcome)") + return + } + #expect(try storage.holdsReservation(for: refusedKey)) + refusedReceipt.release() + #expect(try !storage.holdsReservation(for: refusedKey)) + receipt.release() + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift index 7e306ca64..0fefd28cf 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift @@ -16,21 +16,6 @@ import ModelsR4 import Testing -/// Counts the ledger writes a sequencer makes. -private final class CountingStorage: ExchangeEventSequencer.Storage, @unchecked Sendable { - private let lock = NSLock() - private var data: Data? - private(set) var updates = 0 - - func update(_ body: (inout Data?) throws -> R) throws -> R { - lock.lock() - defer { lock.unlock() } - updates += 1 - return try body(&data) - } -} - - /// The exporter is a facade over the conversion the goldens pin: its graphs are byte-identical to the old /// entry point's under the same event, and it adds the event bookkeeping and policies the entry point left /// to the caller. @@ -54,11 +39,10 @@ struct HealthKitFHIRExporterTests { return try HealthKitFHIRExporter(producer: producer, repositoryScope: base.repositoryScope, options: options) } - /// The old entry point's graph for `sample` under the exporter's own producer instance and `sequence`. + /// The old entry point's graph for `sample` under `event`, the one the exporter minted for it. private static func reference( _ sample: HKSample, - exporter: HealthKitFHIRExporter, - sequence: UInt64, + event: ExchangeEventIdentifier?, instant: Date, _ configure: (inout HealthKitConversionOptions) -> Void = { _ in } ) throws -> HealthKitConversion { @@ -67,11 +51,7 @@ struct HealthKitFHIRExporterTests { let context = HealthKitConversionContext( event: ExchangeEventContext( subject: base.subject, - event: try ExchangeEventIdentifier( - system: base.identityScope.systems.event, - producerInstance: try exporter.producer.sequencer.producerInstance, - sequence: EventSequence(sequence) - ), + event: try #require(event), identityScope: base.identityScope, repositoryScope: base.repositoryScope, application: base.application, @@ -93,6 +73,11 @@ struct HealthKitFHIRExporterTests { return (exports, receipt) } + /// The sequences a call minted, in the order the exports name them. + private static func sequences(_ exports: [HealthKitFHIRExporter.Export]) -> [String] { + exports.compactMap(\.sequence) + } + @Test("Graphs equal the old entry point's under the same event, with the same warnings") func graphsEqualReference() throws { let exporter = try Self.exporter() @@ -101,8 +86,8 @@ struct HealthKitFHIRExporterTests { let (exports, _) = try Self.collect(exporter, [withDevice, withoutToken]) try #require(exports.count == 2) let instant = GoldenFixtures.conversionInstant - let first = try Self.reference(withDevice, exporter: exporter, sequence: 1, instant: instant) - let second = try Self.reference(withoutToken, exporter: exporter, sequence: 2, instant: instant) + let first = try Self.reference(withDevice, event: exports[0].event, instant: instant) + let second = try Self.reference(withoutToken, event: exports[1].event, instant: instant) #expect(exports[0].graph?.json == first.graph.json) #expect(exports[1].graph?.json == second.graph.json) #expect(exports[0].source == HealthKitFHIRExporter.Export.Source(uuid: GoldenFixtures.uuid(1), typeIdentifier: HKQuantityTypeIdentifier.heartRate.rawValue)) @@ -110,8 +95,9 @@ struct HealthKitFHIRExporterTests { #expect(exports[0].warnings.isEmpty) #expect(exports[1].warnings == second.warnings.map(\.diagnostic)) #expect(exports[1].warnings.contains(ExchangeGraphRule.mobileOmissionRecordingDevice.diagnostic)) - #expect(exports[0].graph?.event.value == "e0:\(try exporter.producer.sequencer.producerInstance.uuidString.lowercased()):1") - #expect(exports[1].graph?.event.value.hasSuffix(":2") == true) + // New events number consecutively in the sorted order of their requests, under one producer instance. + #expect(Set(Self.sequences(exports)) == ["1", "2"]) + #expect(exports[0].event?.producerInstance == exports[1].event?.producerInstance) } @Test("A redelivery before release reproduces the same bytes; after release it is a new event") @@ -123,20 +109,21 @@ struct HealthKitFHIRExporterTests { #expect(first[0].graph?.json == again[0].graph?.json) receipt.release() let (afterRelease, _) = try Self.collect(exporter, [sample]) - #expect(afterRelease[0].graph?.event.value.hasSuffix(":2") == true) + #expect(afterRelease[0].sequence == "2") #expect(afterRelease[0].graph?.json != first[0].graph?.json) } - @Test("An unconvertible record is refused in place, releases its reservation, and the export continues") + @Test("An unconvertible record is refused in place, holds its reservation until the receipt is released, and the export continues") func refusalsDoNotEndTheExport() throws { - let exporter = try Self.exporter() + let storage = LedgerCountingStorage() + let exporter = try Self.exporter(sequencer: ExchangeEventSequencer(storage: storage)) let ecg = try StoredSampleFixtures.seriesSample( HKElectrocardiogram.self, sampleType: HKObjectType.electrocardiogramType(), shape: GoldenCase.seriesShape(uuid: 4, duration: 30) ) let heartRate = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(5)) - let (exports, _) = try Self.collect(exporter, [ecg, heartRate]) + let (exports, receipt) = try Self.collect(exporter, [ecg, heartRate]) try #require(exports.count == 2) guard case .refused(let reason) = exports[0].outcome else { Issue.record("expected a refusal, got \(exports[0].outcome)") @@ -144,15 +131,20 @@ struct HealthKitFHIRExporterTests { } #expect(reason == .ecgEvidence(.evidenceRequired)) #expect(exports[0].graph == nil) - #expect(exports[1].graph?.event.value.hasSuffix(":2") == true) - // The refused ECG's reservation was released, so the next export of it takes a fresh sequence. - let (retry, _) = try Self.collect(exporter, [ecg]) + #expect(["1", "2"].contains(exports[1].sequence ?? "")) + // Nothing is released mid-call: the refused ECG keeps its reservation until the receipt is released. + let ecgKey = try #require(ExchangeEventKey.active(ecg)) + #expect(try storage.holdsReservation(for: ecgKey)) + let (retry, retryReceipt) = try Self.collect(exporter, [ecg]) guard case .refused = retry[0].outcome else { Issue.record("expected a refusal") return } let (next, _) = try Self.collect(exporter, [try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(6))]) - #expect(next[0].graph?.event.value.hasSuffix(":4") == true) + #expect(next[0].sequence == "3", "the refused ECG's redelivery reused its reservation") + receipt.release() + retryReceipt.release() + #expect(try !storage.holdsReservation(for: ecgKey)) } @Test("Under the automatic writer policy an Apple per-device source is the recording Device that authored the sample") @@ -181,7 +173,7 @@ struct HealthKitFHIRExporterTests { #expect(author?.who.reference?.value?.string == recorderURL) #expect(exports[0].warnings.isEmpty) // The application source converts exactly as the old entry point's default (`.application`) did. - let reference = try Self.reference(fromApp, exporter: exporter, sequence: 2, instant: GoldenFixtures.conversionInstant) + let reference = try Self.reference(fromApp, event: exports[1].event, instant: GoldenFixtures.conversionInstant) #expect(exports[1].graph?.json == reference.graph.json) } @@ -205,7 +197,7 @@ struct HealthKitFHIRExporterTests { #expect(bundle.entry?.compactMap { $0.resource?.get(if: Provenance.self) }.first?.entity?.first?.agent == nil) let observation = try #require(bundle.entry?.compactMap { $0.resource?.get(if: Observation.self) }.first) #expect(observation.identifier?.contains { $0.system?.value?.url.absoluteString == GoldenFixtures.nativeIdentifierSystem.rawValue } == true) - let reference = try Self.reference(sample, exporter: exporter, sequence: 1, instant: GoldenFixtures.conversionInstant) { options in + let reference = try Self.reference(sample, event: exports[0].event, instant: GoldenFixtures.conversionInstant) { options in options.writer = .omit options.udiDisclosure = .authorizedUDI options.nativeIdentifierDisclosure = .authorized(system: GoldenFixtures.nativeIdentifierSystem) @@ -242,11 +234,11 @@ struct HealthKitFHIRExporterTests { return } #expect(exports.map(\.source.uuid) == [GoldenFixtures.uuid(10), GoldenFixtures.uuid(11), GoldenFixtures.uuid(12)]) - let producerInstance = try exporter.producer.sequencer.producerInstance - for (export, sequence, deletion) in [(exports[0], UInt64(1), deletions[0]), (exports[2], 2, deletions[2])] { + #expect(Set(Self.sequences(exports)) == ["1", "2"]) + for (export, deletion) in [(exports[0], deletions[0]), (exports[2], deletions[2])] { let context = HealthKitConversionContext(event: ExchangeEventContext( subject: Self.base.subject, - event: try ExchangeEventIdentifier(system: Self.base.identityScope.systems.event, producerInstance: producerInstance, sequence: EventSequence(sequence)), + event: try #require(export.event), identityScope: Self.base.identityScope, repositoryScope: Self.base.repositoryScope, application: Self.base.application, @@ -262,12 +254,12 @@ struct HealthKitFHIRExporterTests { } receipt.release() let (afterRelease, _) = try Self.collect(exporter, [try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(13))]) - #expect(afterRelease[0].graph?.event.value.hasSuffix(":3") == true) + #expect(afterRelease[0].sequence == "3") } @Test("Deletions of types without outputs touch no ledger; a skewed lower bound is dropped, Bundle.id follows the legacy policy") func retractionBoundsAndLedger() throws { - let storage = CountingStorage() + let storage = LedgerCountingStorage() let exporter = try Self.exporter({ $0.legacyBundleID = .healthKitUUID }, sequencer: ExchangeEventSequencer(storage: storage)) let detectedAt = GoldenFixtures.conversionInstant var exports: [HealthKitFHIRExporter.Export] = [] @@ -275,9 +267,9 @@ struct HealthKitFHIRExporterTests { [HealthKitFHIRExporter.Deletion(uuid: GoldenFixtures.uuid(20), sourceType: .bloodPressureSystolic, deletedAfter: nil, detectedAt: detectedAt)], at: detectedAt ) { exports.append($0) } - #expect(storage.updates == 0) + #expect(storage.take().transactions == 0) _ = try exporter.export([HKSample](), at: detectedAt) { exports.append($0) } - #expect(storage.updates == 0) + #expect(storage.take().transactions == 0) _ = try exporter.retract( [HealthKitFHIRExporter.Deletion(uuid: GoldenFixtures.uuid(21), sourceType: .heartRate, deletedAfter: detectedAt + 60, detectedAt: detectedAt)], at: detectedAt @@ -302,7 +294,7 @@ struct HealthKitFHIRExporterTests { try exporter.export([sample]) { _ in throw Stop() } } let (again, _) = try Self.collect(exporter, [sample]) - #expect(again[0].graph?.event.value.hasSuffix(":1") == true) + #expect(again[0].sequence == "1") } } From 081ea4ee05556913998b359714526324f298995e Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sat, 3 Oct 2026 22:48:20 +0200 Subject: [PATCH 009/220] Build Every Envelope From Frozen Facts and Prepare Facts Once Frozen facts no longer rest on convention. HealthKitAssembly stored a whole ExchangeEnvelope built from the producer's live application, host and studies, and each graph swapped its reservation's facts in through with(_:); a call site that forgot the swap would have stated live facts under a frozen event. - ExchangeEnvelope is now its Scope (adapter, identity scope, subject, repository scope) plus the event's facts. HealthKitAssembly keeps only the Scope and builds ExchangeEnvelope(scope:facts:) per graph from the request's frozen facts; with(_:) is gone, and the exporter no longer hands producer facts to the assembly at all. - ExchangeProducer prepares its facts once at init (encode, digest, decode back through the validating initializers). Facts that do not survive that round trip are a configuration fault, ExchangeProducer.ConfigurationError.unfreezableFacts, instead of a LedgerError.corruptEntry whose remedy (reset) could never fix them. Exporters reserve through ExchangeProducer.reserve(_:at:), which passes those prepared facts, so a call no longer re-encodes, hashes and decodes them. ExchangeEventSequencer.reserve(_:at:facts:) takes the PreparedFacts and is internal. - PreparedFacts decoding no longer throws corruptEntry as control flow from its canonical helper; invalid stored values map to corruptEntry in one place. - The ExchangeProducer init doc names the sequencer as the ledger of sequences and frozen facts, as its property doc already did. Audit ledger: section 2 finding 1 (unfrozen facts), now enforced by construction. G1 review items: design M2, minor 1, the protocolURL nit, minor 3(e). Output unchanged: GroveHealthKitFHIR macOS suite including GoldenGraphTests and the G17 digest table passes with every golden byte-identical; GroveFHIR suite passes. Co-Authored-By: Claude Opus 5.5 --- .../ExchangeEventFacts.swift | 18 +++- .../ExchangeEventSequencer+Facts.swift | 87 +++++++++++-------- .../ExchangeEventSequencer.swift | 8 +- .../ExchangeGraphDraft.swift | 83 +++++++++--------- .../GroveFHIRContract/ExchangeProducer.swift | 10 ++- .../HealthKitAssembly+Records.swift | 4 +- .../HealthKitAssembly.swift | 23 +++-- .../HealthKitFHIRExporter+Retraction.swift | 2 +- .../HealthKitFHIRExporter.swift | 7 +- .../ExchangeEventSequencerTests.swift | 4 +- .../ExchangeLedgerEntryTests.swift | 16 ++-- .../ExchangeLedger/LedgerFixtures.swift | 16 +++- 12 files changed, 162 insertions(+), 116 deletions(-) diff --git a/Sources/GroveFHIRContract/ExchangeEventFacts.swift b/Sources/GroveFHIRContract/ExchangeEventFacts.swift index da74e25cb..2a68dbc8d 100644 --- a/Sources/GroveFHIRContract/ExchangeEventFacts.swift +++ b/Sources/GroveFHIRContract/ExchangeEventFacts.swift @@ -6,7 +6,7 @@ // SPDX-License-Identifier: MIT // -import Foundation +package import Foundation /// What an event states about the converting application, its host and the participant's studies, @@ -29,8 +29,20 @@ package struct ExchangeEventFacts: Hashable, Sendable { extension ExchangeProducer { - /// The facts a new reservation is minted under: this producer's, as captured when it was built. + /// The facts a new reservation is minted under: this producer's, as captured when it was built and decoded + /// back from the ledger's encoding, exactly as every graph states them. package var facts: ExchangeEventFacts { - ExchangeEventFacts(application: application, host: host, studies: studies) + preparedFacts.facts + } + + /// One reservation per distinct request in one ledger transaction, new ones under this producer's facts. + /// + /// See ``ExchangeEventSequencer`` for what a reservation keeps; each returned reservation is held for the + /// caller until it finishes it through the sequencer. + package func reserve( + _ requests: some Collection, + at instant: Date + ) throws -> [ExchangeEventRequest: ExchangeEventReservation] { + try sequencer.reserve(requests, at: instant, facts: preparedFacts) } } diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer+Facts.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer+Facts.swift index 6a03a1d1a..9615ae238 100644 --- a/Sources/GroveFHIRContract/ExchangeEventSequencer+Facts.swift +++ b/Sources/GroveFHIRContract/ExchangeEventSequencer+Facts.swift @@ -19,8 +19,8 @@ import ModelsR4 /// /// The digest is the SHA-256, base64url without padding, of the entry's bytes, so equal facts share one /// entry across producer instances; a reservation names its digest, so an encoding that differs on another -/// platform only misses a deduplication. -struct PreparedFacts { +/// platform only misses a deduplication. A producer prepares its facts once, when it is built. +struct PreparedFacts: Sendable { private struct Payload: Codable { enum CodingKeys: String, CodingKey { case version = "v" @@ -67,7 +67,9 @@ struct PreparedFacts { /// The facts as every graph sees them: decoded from ``bytes``, never the caller's values. let facts: ExchangeEventFacts - init(_ facts: ExchangeEventFacts) throws { + /// Encodes `facts` and decodes them back the way a redelivery decodes the stored entry; `nil` when they do + /// not survive that round trip, so no event could freeze them. + init?(_ facts: ExchangeEventFacts) { let payload = Payload( version: LedgerEntryCoding.version, application: ApplicationPayload( @@ -93,54 +95,69 @@ struct PreparedFacts { ) } ) - let bytes = try LedgerEntryCoding.encode(payload) + guard let bytes = try? LedgerEntryCoding.encode(payload) else { + return nil + } let digest = Data(SHA256.hash(data: bytes)).base64URLEncodedStringWithoutPadding + guard let decoded = try? Self.decode(bytes, key: LedgerKey.facts(digest)) else { + return nil + } self.bytes = bytes self.digest = digest - self.facts = try Self.decode(bytes, key: LedgerKey.facts(digest)) + self.facts = decoded } /// Rebuilds stored facts through the validating initializers; any fault makes the entry corrupt. static func decode(_ value: Data, key: String) throws -> ExchangeEventFacts { let payload = try LedgerEntryCoding.decode(Payload.self, from: value, key: key) - do { - let application = try ApplicationDevice( - name: payload.application.name, - bundleIdentifier: payload.application.bundleIdentifier, - version: payload.application.version, - build: payload.application.build - ) - let host = try HostDevice( - operatingSystemVersion: payload.host.operatingSystemVersion, - name: payload.host.name, - manufacturer: payload.host.manufacturer, - modelNumber: payload.host.modelNumber - ) - let studies = try payload.studies.map { study in - try StudyEnrollment( - study: try identifier(study.study), - protocolURL: try protocolURL(study.protocolURL), - protocolVersion: study.protocolVersion, - enrollment: try identifier(study.enrollment) - ) - } - return ExchangeEventFacts(application: application, host: host, studies: studies) - } catch { + guard let facts = facts(from: payload) else { throw ExchangeEventSequencer.LedgerError.corruptEntry(key: key) } + return facts + } + + /// The facts a payload states, or `nil` when any validating initializer refuses a value. + private static func facts(from payload: Payload) -> ExchangeEventFacts? { + guard let application = try? ApplicationDevice( + name: payload.application.name, + bundleIdentifier: payload.application.bundleIdentifier, + version: payload.application.version, + build: payload.application.build + ), let host = try? HostDevice( + operatingSystemVersion: payload.host.operatingSystemVersion, + name: payload.host.name, + manufacturer: payload.host.manufacturer, + modelNumber: payload.host.modelNumber + ) else { + return nil + } + var studies: [StudyEnrollment] = [] + for study in payload.studies { + guard let studyIdentifier = identifier(study.study), + let enrollmentIdentifier = identifier(study.enrollment), + let canonical = protocolURL(study.protocolURL), + let rebuilt = try? StudyEnrollment( + study: studyIdentifier, + protocolURL: canonical, + protocolVersion: study.protocolVersion, + enrollment: enrollmentIdentifier + ) else { + return nil + } + studies.append(rebuilt) + } + return ExchangeEventFacts(application: application, host: host, studies: studies) } - private static func identifier(_ payload: IdentifierPayload) throws -> BusinessIdentifier { - try BusinessIdentifier(system: IdentifierSystem(payload.system), value: payload.value) + private static func identifier(_ payload: IdentifierPayload) -> BusinessIdentifier? { + try? BusinessIdentifier(system: IdentifierSystem(payload.system), value: payload.value) } - private static func protocolURL(_ text: String?) throws -> FHIRPrimitive { + /// The canonical as written; an absent one is an empty primitive, text that is no canonical is `nil`. + private static func protocolURL(_ text: String?) -> FHIRPrimitive? { guard let text else { return FHIRPrimitive() } - guard let canonical = text.asFHIRCanonicalPrimitive() else { - throw ExchangeEventSequencer.LedgerError.corruptEntry(key: text) - } - return canonical + return text.asFHIRCanonicalPrimitive() } } diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift index 4480ea402..4cad0609f 100644 --- a/Sources/GroveFHIRContract/ExchangeEventSequencer.swift +++ b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift @@ -140,13 +140,13 @@ extension ExchangeEventSequencer { /// request takes the next sequence at `instant` (millisecond precision) under `facts`, replacing what /// the key held. New sequences follow the requests' sorted order; a counter that would overflow mints /// a new producer instance. A sequence is never handed out twice. Each returned reservation is held - /// for the caller until ``finish(_:released:forgetting:)``. - package func reserve( + /// for the caller until ``finish(_:released:forgetting:)``. Exporters reach it through + /// `ExchangeProducer.reserve(_:at:)`, which passes the facts the producer prepared once. + func reserve( _ requests: some Collection, at instant: Date, - facts: ExchangeEventFacts + facts current: PreparedFacts ) throws -> [ExchangeEventRequest: ExchangeEventReservation] { - let current = try PreparedFacts(facts) let ordered = Set(requests).sorted { ($0.key.rawValue, $0.fingerprint) < ($1.key.rawValue, $1.fingerprint) } let instantMilliseconds = ExchangeInstant.millisecondsSinceEpoch(instant) let reserved = try storage.transaction { transaction in diff --git a/Sources/GroveFHIRContract/ExchangeGraphDraft.swift b/Sources/GroveFHIRContract/ExchangeGraphDraft.swift index 44a72d13c..bb671320c 100644 --- a/Sources/GroveFHIRContract/ExchangeGraphDraft.swift +++ b/Sources/GroveFHIRContract/ExchangeGraphDraft.swift @@ -34,56 +34,59 @@ package struct ExchangeAdapterContract: Sendable { } -/// What one graph states about its producer and source repository beside the record itself. +/// What one graph states about its producer and source repository beside the record itself: the scope every +/// event of one producer shares, and the facts frozen with this event. /// -/// The scope half (adapter, identity scope, subject, repository scope) is the same for every event a -/// producer emits; the facts (application, host, studies) are each event's own, frozen at its reservation, -/// and ``with(_:)`` swaps them in per event. +/// An envelope is built per event from its reservation's facts, so no graph can state a producer's live +/// application, host or studies; whatever outlives one event holds only the ``Scope``. package struct ExchangeEnvelope: Sendable { - package let adapter: ExchangeAdapterContract - package let identityScope: OpaqueIdentityScope - package let subject: Subject - package let repositoryScope: BusinessIdentifier + /// What every event of one producer states identically: the adapter, the identity scope, the subject and + /// the repository scope. It carries no application, host or studies. + package struct Scope: Sendable { + package let adapter: ExchangeAdapterContract + package let identityScope: OpaqueIdentityScope + package let subject: Subject + package let repositoryScope: BusinessIdentifier + + package init( + adapter: ExchangeAdapterContract, + identityScope: OpaqueIdentityScope, + subject: Subject, + repositoryScope: BusinessIdentifier + ) { + self.adapter = adapter + self.identityScope = identityScope + self.subject = subject + self.repositoryScope = repositoryScope + } + + /// The source-record identity of one native record in this repository. + package func sourceRecord(sourceType: String, nativeRecordID: String) throws(OpaqueIdentityError) -> SourceRecordIdentity { + try identityScope.sourceRecord( + adapterID: adapter.adapterID, + sourceType: sourceType, + repositoryScope: repositoryScope, + nativeRecordID: nativeRecordID + ) + } + } + + package let scope: Scope + /// The application, host and studies the event states, as its reservation froze them. package let facts: ExchangeEventFacts + package var adapter: ExchangeAdapterContract { scope.adapter } + package var identityScope: OpaqueIdentityScope { scope.identityScope } + package var subject: Subject { scope.subject } + package var repositoryScope: BusinessIdentifier { scope.repositoryScope } package var application: ApplicationDevice { facts.application } package var host: HostDevice { facts.host } package var studies: [StudyEnrollment] { facts.studies } - package init( - adapter: ExchangeAdapterContract, - identityScope: OpaqueIdentityScope, - subject: Subject, - repositoryScope: BusinessIdentifier, - facts: ExchangeEventFacts - ) { - self.adapter = adapter - self.identityScope = identityScope - self.subject = subject - self.repositoryScope = repositoryScope + package init(scope: Scope, facts: ExchangeEventFacts) { + self.scope = scope self.facts = facts } - - /// The same scope under one event's facts. - package func with(_ facts: ExchangeEventFacts) -> ExchangeEnvelope { - ExchangeEnvelope( - adapter: adapter, - identityScope: identityScope, - subject: subject, - repositoryScope: repositoryScope, - facts: facts - ) - } - - /// The source-record identity of one native record in this repository. - package func sourceRecord(sourceType: String, nativeRecordID: String) throws(OpaqueIdentityError) -> SourceRecordIdentity { - try identityScope.sourceRecord( - adapterID: adapter.adapterID, - sourceType: sourceType, - repositoryScope: repositoryScope, - nativeRecordID: nativeRecordID - ) - } } diff --git a/Sources/GroveFHIRContract/ExchangeProducer.swift b/Sources/GroveFHIRContract/ExchangeProducer.swift index d9972c293..5e4f58dd7 100644 --- a/Sources/GroveFHIRContract/ExchangeProducer.swift +++ b/Sources/GroveFHIRContract/ExchangeProducer.swift @@ -23,6 +23,8 @@ public final class ExchangeProducer: Sendable { case duplicateStudy(BusinessIdentifier) /// Two enrollments carry the same enrollment identifier. case duplicateEnrollment(BusinessIdentifier) + /// The application, host or studies do not survive the ledger's encoding, so no event could freeze them. + case unfreezableFacts /// The registered diagnostic: every configuration fault is a deployment defect. public var diagnostic: ProducerDiagnostic { @@ -42,6 +44,8 @@ public final class ExchangeProducer: Sendable { public let studies: [StudyEnrollment] /// The ledger the producer's events take their sequences and frozen facts from. public let sequencer: ExchangeEventSequencer + /// The application, host and studies as the ledger stores them, encoded once here for every reservation. + let preparedFacts: PreparedFacts /// Creates the producer of one installation. /// @@ -51,7 +55,7 @@ public final class ExchangeProducer: Sendable { /// - application: The converting application, as its Device snapshot states it. /// - host: The host the application runs on; captured now, as a later snapshot may differ. /// - studies: The participant's known enrollments, each study once. - /// - sequencer: Where the producer's events take their sequences from. + /// - sequencer: The ledger the producer's events take their sequences and frozen facts from. public init( identityScope: OpaqueIdentityScope, subject: Subject, @@ -77,11 +81,15 @@ public final class ExchangeProducer: Sendable { throw .duplicateEnrollment(enrollment.enrollment) } } + guard let preparedFacts = PreparedFacts(ExchangeEventFacts(application: application, host: host, studies: studies)) else { + throw .unfreezableFacts + } self.identityScope = identityScope self.subject = subject self.application = application self.host = host self.studies = studies self.sequencer = sequencer + self.preparedFacts = preparedFacts } } diff --git a/Sources/GroveHealthKitFHIR/HealthKitAssembly+Records.swift b/Sources/GroveHealthKitFHIR/HealthKitAssembly+Records.swift index 64654a3bc..6edef0968 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitAssembly+Records.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitAssembly+Records.swift @@ -107,7 +107,7 @@ extension HealthKitAssembly { private func validatedSymptomOutputIdentifiers(_ conversions: [HealthKitConversion]) throws -> [RoledIdentifier] { let outputs = conversions.map(\.identifiers.primaryOutput) - let expectedSystem = envelope.identityScope.systems.opaque.sourceOutput + let expectedSystem = scope.identityScope.systems.opaque.sourceOutput guard outputs.allSatisfy({ $0.role == .sourceOutput && $0.identifier.system == expectedSystem }) else { throw HealthKitConversionError.ecgEvidence(.invalidSymptomOutputIdentity) } @@ -274,7 +274,7 @@ extension HealthKitAssembly { private func sourceRecordIdentity(of record: HealthKitSourceRecord) throws(HealthKitConversionError) -> SourceRecordIdentity { do { - return try envelope.sourceRecord(sourceType: record.type.rawValue, nativeRecordID: record.uuid.uuidString.lowercased()) + return try scope.sourceRecord(sourceType: record.type.rawValue, nativeRecordID: record.uuid.uuidString.lowercased()) } catch { throw .opaqueIdentity(error) } diff --git a/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift b/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift index e5c1a1caf..6dd8c2e5c 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift @@ -80,20 +80,19 @@ struct HealthKitAssembly: Sendable { ) } - /// The producer's scope; each graph takes its own request's facts. - let envelope: ExchangeEnvelope + /// The producer's scope. It holds no facts: each graph's envelope takes its own request's frozen facts. + let scope: ExchangeEnvelope.Scope - init(envelope: ExchangeEnvelope) { - self.envelope = envelope + init(scope: ExchangeEnvelope.Scope) { + self.scope = scope } init(context: ExchangeEventContext) { - self.init(envelope: ExchangeEnvelope( + self.init(scope: ExchangeEnvelope.Scope( adapter: Self.adapter, identityScope: context.identityScope, subject: context.subject, - repositoryScope: context.repositoryScope, - facts: ExchangeEventFacts(context) + repositoryScope: context.repositoryScope )) } @@ -147,14 +146,14 @@ struct HealthKitAssembly: Sendable { let draft = ExchangeGraphDraft( event: request.event, instant: request.instant, - sourceRecord: try envelope.sourceRecord(sourceType: type.rawValue, nativeRecordID: sample.uuid.uuidString.lowercased()), + sourceRecord: try scope.sourceRecord(sourceType: type.rawValue, nativeRecordID: sample.uuid.uuidString.lowercased()), outputs: outputs, recordingDevice: facts.recordingDevice, writer: facts.writer, converterRole: request.converterRole, repositoryIDs: request.repositoryIDs ) - let assembled = try ExchangeGraphAssembler(envelope: envelope.with(request.facts)).assemble(draft) + let assembled = try ExchangeGraphAssembler(envelope: ExchangeEnvelope(scope: scope, facts: request.facts)).assemble(draft) return HealthKitConversion( source: source, identifiers: assembled.identifiers, @@ -200,10 +199,10 @@ extension HealthKitAssembly { /// The event context a retraction or a bundled study context is minted from, under the request's facts. func eventContext(for request: Request) -> ExchangeEventContext { ExchangeEventContext( - subject: envelope.subject, + subject: scope.subject, event: request.event, - identityScope: envelope.identityScope, - repositoryScope: envelope.repositoryScope, + identityScope: scope.identityScope, + repositoryScope: scope.repositoryScope, application: request.facts.application, host: request.facts.host, conversionInstant: request.instant, diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift index 3d250f5c2..7913356fe 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift @@ -32,7 +32,7 @@ extension HealthKitFHIRExporter { isRetractable(deletion) ? context.request(for: .retraction(deletion), recordParts: deletion.occurrenceParts) : nil } let unique = Set(requests.compactMap(\.self)) - let reserved = unique.isEmpty ? [:] : try producer.sequencer.reserve(unique, at: instant, facts: producer.facts) + let reserved = unique.isEmpty ? [:] : try producer.reserve(unique, at: instant) // Created before any delivery: when a delivery throws, the receipt is dropped and its holds lapse. let receipt = Receipt( sequencer: producer.sequencer, diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift index bb4179824..ded1ea75b 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift @@ -59,12 +59,11 @@ public final class HealthKitFHIRExporter: Sendable { self.producer = producer self.repositoryScope = repositoryScope self.options = options - self.assembly = HealthKitAssembly(envelope: ExchangeEnvelope( + self.assembly = HealthKitAssembly(scope: ExchangeEnvelope.Scope( adapter: HealthKitAssembly.adapter, identityScope: producer.identityScope, subject: producer.subject, - repositoryScope: repositoryScope, - facts: producer.facts + repositoryScope: repositoryScope )) self.context = ExportContext(producer: producer, repositoryScope: repositoryScope, options: options, revisions: outputRevisions) } @@ -94,7 +93,7 @@ public final class HealthKitFHIRExporter: Sendable { let plans = inputs.map { Plan($0, context: context) } let requests = Set(plans.flatMap(\.requests)) // Nothing reserved means the ledger is never touched; refusals alone need no event. - let reserved = requests.isEmpty ? [:] : try producer.sequencer.reserve(requests, at: instant, facts: producer.facts) + let reserved = requests.isEmpty ? [:] : try producer.reserve(requests, at: instant) // Created before any delivery: when a delivery throws, the receipt is dropped and its holds lapse. let receipt = Receipt(sequencer: producer.sequencer, held: reserved.values.map(\.handle), forgetting: []) for plan in plans { diff --git a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventSequencerTests.swift b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventSequencerTests.swift index a965278bf..8a02831de 100644 --- a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventSequencerTests.swift +++ b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventSequencerTests.swift @@ -45,7 +45,7 @@ struct ExchangeEventSequencerTests { _ = storage.takeCounts() let again = try sequencer.reserve([request], at: Fixtures.instant.addingTimeInterval(3600), facts: Fixtures.facts(build: "110")) #expect(again == first) - #expect(again[request]?.facts == (try Fixtures.facts(build: "100"))) + #expect(again[request]?.facts == (try Fixtures.facts(build: "100").facts)) let counts = storage.takeCounts() #expect(counts.writes == 0 && counts.removals == 0) #expect(counts.transactions == 1) @@ -135,7 +135,7 @@ struct ExchangeEventSequencerTests { let producer = try #require(try Fixtures.stored(LedgerKey.producer, in: storage)) #expect(String(decoding: producer, as: UTF8.self) == #"{"instance":"\#(instance)","next":"2","v":1}"#) let event = try #require(try Fixtures.stored(LedgerKey.event(request.key), in: storage)) - let digest = try PreparedFacts(Fixtures.facts()).digest + let digest = try Fixtures.facts().digest #expect(String(decoding: event, as: UTF8.self) == #"{"facts":"\#(digest)","fingerprint":"context-a","instance":"\#(instance)","instant":1791023400251,"sequence":"1","v":1}"#) #expect(try Fixtures.keys("", in: storage) == [LedgerKey.producer, LedgerKey.event(request.key), LedgerKey.facts(digest)]) diff --git a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerEntryTests.swift b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerEntryTests.swift index a4b9f1314..c107b77cd 100644 --- a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerEntryTests.swift +++ b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerEntryTests.swift @@ -55,7 +55,7 @@ struct ExchangeLedgerEntryTests { /// A ledger holding one reservation for `a` under `instance`, with the current facts stored. private static func seededLedger(event: String, producer: String? = nil) throws -> ExchangeEventSequencer.InMemoryStorage { let storage = ExchangeEventSequencer.InMemoryStorage() - let facts = try PreparedFacts(Fixtures.facts()) + let facts = try Fixtures.facts() try storage.transaction { try $0.write(facts.bytes, for: LedgerKey.facts(facts.digest)) } try Fixtures.seed( [ @@ -82,17 +82,17 @@ struct ExchangeLedgerEntryTests { host: try HostDevice(operatingSystemVersion: "26.0.1"), studies: studies ) - let prepared = try PreparedFacts(facts) + let prepared = try Fixtures.prepared(facts) #expect(prepared.facts == facts) #expect(try PreparedFacts.decode(prepared.bytes, key: "facts/x") == facts) - #expect(try PreparedFacts(prepared.facts).bytes == prepared.bytes, "encoding is deterministic") - #expect(try PreparedFacts(Fixtures.facts(build: "101")).digest != prepared.digest) + #expect(try Fixtures.prepared(prepared.facts).bytes == prepared.bytes, "encoding is deterministic") + #expect(try Fixtures.facts(build: "101").digest != prepared.digest) let current = ExchangeEventFacts( application: try ApplicationDevice(name: "Grove Test", bundleIdentifier: "org.grovealliance.test", version: "1.0"), host: HostDevice.current(), studies: [] ) - #expect(try PreparedFacts(current).facts == current) + #expect(try Fixtures.prepared(current).facts == current) } @Test("Equal facts are stored once and shared across reservations and instances") @@ -131,7 +131,7 @@ struct ExchangeLedgerEntryTests { let kept = try sequencer.reserve([Fixtures.request("new")], at: start + 120, facts: Fixtures.facts(build: "2")) #expect(try sequencer.forgetReservations(madeBefore: start) == 0) #expect(try sequencer.forgetReservations(madeBefore: start + 60) == 2) - #expect(try Fixtures.keys(LedgerKey.factsPrefix, in: storage) == [LedgerKey.facts(try PreparedFacts(Fixtures.facts(build: "2")).digest)]) + #expect(try Fixtures.keys(LedgerKey.factsPrefix, in: storage) == [LedgerKey.facts(try Fixtures.facts(build: "2").digest)]) #expect(try sequencer.forgetReservations(madeBefore: start + 61) == 1) #expect(try Fixtures.keys(LedgerKey.eventPrefix, in: storage) == [LedgerKey.event(Fixtures.key("new"))]) #expect(try sequencer.reserve([Fixtures.request("new")], at: start + 500, facts: Fixtures.facts(build: "3")) == kept) @@ -167,12 +167,12 @@ struct ExchangeLedgerEntryTests { let retired = try Self.seededLedger(event: Self.event(instance: "2eafba7b-4c21-4bf5-ad46-351b0176b25a", sequence: "8")) #expect(try Fixtures.sequencer(retired).reserve([request], at: Fixtures.instant, facts: facts)[request]?.sequence.rawValue == "8") let missingFacts = try Self.seededLedger(event: Self.event()) - try missingFacts.transaction { try $0.remove(LedgerKey.facts(try PreparedFacts(facts).digest)) } + try missingFacts.transaction { try $0.remove(LedgerKey.facts(facts.digest)) } #expect(throws: ExchangeEventSequencer.LedgerError.corruptEntry(key: eventKey)) { try Fixtures.sequencer(missingFacts).reserve([request], at: Fixtures.instant, facts: facts) } let blankName = try Self.seededLedger(event: Self.event()) - let factsKey = LedgerKey.facts(try PreparedFacts(facts).digest) + let factsKey = LedgerKey.facts(facts.digest) let stored = String(decoding: try #require(try Fixtures.stored(factsKey, in: blankName)), as: UTF8.self) try Fixtures.seed([factsKey: stored.replacingOccurrences(of: #""name":"Grove Test""#, with: #""name":" ""#)], in: blankName) #expect(throws: ExchangeEventSequencer.LedgerError.corruptEntry(key: factsKey)) { diff --git a/Tests/GroveFHIRTests/ExchangeLedger/LedgerFixtures.swift b/Tests/GroveFHIRTests/ExchangeLedger/LedgerFixtures.swift index 1782ae059..fafb3dd93 100644 --- a/Tests/GroveFHIRTests/ExchangeLedger/LedgerFixtures.swift +++ b/Tests/GroveFHIRTests/ExchangeLedger/LedgerFixtures.swift @@ -14,6 +14,7 @@ import ModelsR4 /// Fixtures the ledger tests share. enum LedgerFixtures { struct InvalidCanonical: Error {} + struct UnfreezableFacts: Error {} static let instant = Date(timeIntervalSince1970: 1_791_023_400.251) static let instantMilliseconds: Int64 = 1_791_023_400_251 @@ -26,13 +27,20 @@ enum LedgerFixtures { ExchangeEventRequest(key: key(record, kind: kind), fingerprint: fingerprint) } - /// Facts naming application build `build`, so tests can tell facts apart. - static func facts(build: String = "100", operatingSystem: String = "26.0", studies: [StudyEnrollment] = []) throws -> ExchangeEventFacts { - ExchangeEventFacts( + /// Facts naming application build `build`, so tests can tell facts apart, prepared as a producer prepares them. + static func facts(build: String = "100", operatingSystem: String = "26.0", studies: [StudyEnrollment] = []) throws -> PreparedFacts { + try prepared(ExchangeEventFacts( application: try ApplicationDevice(name: "Grove Test", bundleIdentifier: "org.grovealliance.test", version: "1.0", build: build), host: try HostDevice(operatingSystemVersion: operatingSystem, name: "Host", manufacturer: "Example", modelNumber: "Phone1"), studies: studies - ) + )) + } + + static func prepared(_ facts: ExchangeEventFacts) throws -> PreparedFacts { + guard let prepared = PreparedFacts(facts) else { + throw UnfreezableFacts() + } + return prepared } static func enrollment(_ name: String, protocolURL: String, version: String = "1") throws -> StudyEnrollment { From 4638c3582078adb51107299778a8e3f0a02e86bd Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sat, 3 Oct 2026 22:50:01 +0200 Subject: [PATCH 010/220] Remove Dead Ledger State and Duplicated Checks Cleanup from the G1 review of the exchange ledger; no behaviour changes. - One RFC 4122 check: a stored producer instance is validated with ExchangeEventIdentifier.statesRFC4122Version, the check every event identifier already passes, instead of a second bit-level copy in LedgerEntryCoding. - One digest-form check: ExchangeIdentity.isUnpaddedBase64URLDigest (43 characters of base64url) serves both the opaque-identity validator and the ledger's facts digests; LedgerEntryCoding.isDigest is gone. - Dead state removed: ExportContext.callParts (never read; only the framed bytes are used), ExchangeEventKey's Codable conformance (nothing encodes keys since the ledger stores them as entry keys), CountingStorage.snapshot (unused). The reservation's sequence is computed from its handle instead of stored twice. - Renames: ReserveTransaction is ReserveCall (it is one reserve call, not a Transaction conformer); EventEntry.facts is factsDigest (the stored JSON member keeps its name "facts", so the entry layout is unchanged). - The keyed ECG symptom lookup can no longer miss: validation admits only the seven symptom types, all registered source types, and the exporter plans a request for every registered symptom; the positional shape keys every symptom. The unreachable symptomContextCountMismatch throw is a preconditionFailure naming that invariant. - A bundled Patient that cannot be encoded fingerprints as the constant "unencodable" instead of a random UUID, so the fingerprint is deterministic; no JSON text equals it, and such a subject's events never carry a graph. - G6 sleeps with Task.sleep(nanoseconds:), which the iOS 15 / macOS 12 floor has. - CountingStorage's doc says it counts totals over every key, which is what G15 bounds. Not changed: LedgerCountingStorage (GroveHealthKitFHIRTests) and CountingStorage (GroveFHIRTests) stay separate, as SwiftPM test targets cannot share sources and a shared test-support target for one helper is disproportionate. G1 review items: design minor 4 (RFC 4122 and digest), minor 5 (callParts, Codable, reservation sequence, CountingStorage.snapshot), nits (ReserveTransaction, EventEntry.facts, unreachable keyed miss, subject fallback, Task.sleep). HoldRegistry's test-only count/isEmpty go with the hold-registry change that follows. Output unchanged: GroveHealthKitFHIR macOS suite (goldens and the G17 digest table) and GroveFHIR suite pass. Co-Authored-By: Claude Opus 5.5 --- .../ExchangeEventIdentifier.swift | 2 +- .../GroveFHIRContract/ExchangeEventKey.swift | 5 +++-- .../ExchangeEventSequencer+Entries.swift | 19 +++++++++---------- .../ExchangeEventSequencer.swift | 4 ++-- .../GroveFHIRContract/ExchangeIdentity.swift | 10 ++++++---- .../GroveFHIRContract/LedgerEntryCoding.swift | 7 +------ .../HealthKitAssembly+Records.swift | 7 +++---- .../HealthKitFHIRExporter+Fingerprint.swift | 9 ++++----- .../ExchangeLedger/CountingStorage.swift | 11 ++--------- .../ExchangeLedgerPropertyTests.swift | 2 +- 10 files changed, 32 insertions(+), 44 deletions(-) diff --git a/Sources/GroveFHIRContract/ExchangeEventIdentifier.swift b/Sources/GroveFHIRContract/ExchangeEventIdentifier.swift index 0fd9e0330..53ebf9be5 100644 --- a/Sources/GroveFHIRContract/ExchangeEventIdentifier.swift +++ b/Sources/GroveFHIRContract/ExchangeEventIdentifier.swift @@ -49,7 +49,7 @@ public struct ExchangeEventIdentifier: Hashable, Sendable { } /// Whether a canonical UUID text states one of RFC 4122's versions and its variant. - private static func statesRFC4122Version(_ canonicalUUID: String) -> Bool { + static func statesRFC4122Version(_ canonicalUUID: String) -> Bool { let characters = Array(canonicalUUID) guard characters.count == 36 else { return false diff --git a/Sources/GroveFHIRContract/ExchangeEventKey.swift b/Sources/GroveFHIRContract/ExchangeEventKey.swift index bcb43bf6b..8b4818a70 100644 --- a/Sources/GroveFHIRContract/ExchangeEventKey.swift +++ b/Sources/GroveFHIRContract/ExchangeEventKey.swift @@ -41,7 +41,6 @@ package struct ExchangeEventReservation: Hashable, Sendable { } package let handle: Handle - package let sequence: EventSequence /// The instant of the first reservation, at millisecond precision, the same on every return of the key. package let instant: Date /// Always decoded from the ledger's stored facts entry. @@ -49,12 +48,14 @@ package struct ExchangeEventReservation: Hashable, Sendable { /// The producer instance the sequence was handed out under. package var producerInstance: UUID { handle.instance } + /// The event sequence, as the handle states it. + package var sequence: EventSequence { EventSequence(handle.sequence) } } /// The key one exchange event is reserved under: deterministic for one source-record version, and /// opaque, so the ledger holds no clear record identity. -package struct ExchangeEventKey: Hashable, Codable, Sendable { +package struct ExchangeEventKey: Hashable, Sendable { package let rawValue: String } diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer+Entries.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer+Entries.swift index ddafd5340..b1ca9393d 100644 --- a/Sources/GroveFHIRContract/ExchangeEventSequencer+Entries.swift +++ b/Sources/GroveFHIRContract/ExchangeEventSequencer+Entries.swift @@ -75,14 +75,14 @@ struct EventEntry: Equatable { /// Whole milliseconds since 1970-01-01T00:00:00Z. let instantMilliseconds: Int64 /// The digest naming the `facts/` entry. - let facts: String + let factsDigest: String let fingerprint: String - init(instance: UUID, sequence: UInt64, instantMilliseconds: Int64, facts: String, fingerprint: String) { + init(instance: UUID, sequence: UInt64, instantMilliseconds: Int64, factsDigest: String, fingerprint: String) { self.instance = instance self.sequence = sequence self.instantMilliseconds = instantMilliseconds - self.facts = facts + self.factsDigest = factsDigest self.fingerprint = fingerprint } @@ -90,14 +90,14 @@ struct EventEntry: Equatable { let payload = try LedgerEntryCoding.decode(Payload.self, from: value, key: key) guard let instance = LedgerEntryCoding.instance(payload.instance), let sequence = LedgerEntryCoding.positiveInteger(payload.sequence), - LedgerEntryCoding.isDigest(payload.facts) else { + ExchangeIdentity.isUnpaddedBase64URLDigest(payload.facts) else { throw ExchangeEventSequencer.LedgerError.corruptEntry(key: key) } self.init( instance: instance, sequence: sequence, instantMilliseconds: payload.instant, - facts: payload.facts, + factsDigest: payload.facts, fingerprint: payload.fingerprint ) } @@ -108,7 +108,7 @@ struct EventEntry: Equatable { instance: instance.uuidString.lowercased(), sequence: String(sequence), instant: instantMilliseconds, - facts: facts, + facts: factsDigest, fingerprint: fingerprint )) } @@ -120,7 +120,6 @@ extension ExchangeEventReservation { init(key: ExchangeEventKey, entry: EventEntry, facts: ExchangeEventFacts) { self.init( handle: Handle(key: key, instance: entry.instance, sequence: entry.sequence), - sequence: EventSequence(entry.sequence), instant: ExchangeInstant.date(millisecondsSinceEpoch: entry.instantMilliseconds), facts: facts ) @@ -131,7 +130,7 @@ extension ExchangeEventReservation { extension ExchangeEventSequencer { /// One `reserve` call inside its transaction: it reads only the entries of its own keys, the producer, /// and each distinct facts entry once, and writes only what it mints. - struct ReserveTransaction { + struct ReserveCall { private let transaction: any Transaction private let current: PreparedFacts private let instantMilliseconds: Int64 @@ -157,7 +156,7 @@ extension ExchangeEventSequencer { throw LedgerError.corruptEntry(key: key) } if let event, event.fingerprint == request.fingerprint { - reserved[request] = ExchangeEventReservation(key: request.key, entry: event, facts: try facts(event.facts, of: key)) + reserved[request] = ExchangeEventReservation(key: request.key, entry: event, facts: try facts(event.factsDigest, of: key)) continue } if producer.next == .max { @@ -167,7 +166,7 @@ extension ExchangeEventSequencer { instance: producer.instance, sequence: producer.next, instantMilliseconds: instantMilliseconds, - facts: current.digest, + factsDigest: current.digest, fingerprint: request.fingerprint ) producer.next += 1 diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift index 4cad0609f..25eb720cc 100644 --- a/Sources/GroveFHIRContract/ExchangeEventSequencer.swift +++ b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift @@ -119,7 +119,7 @@ public final class ExchangeEventSequencer: Sendable { try transaction.remove(key) forgotten += 1 } else { - referenced.insert(event.facts) + referenced.insert(event.factsDigest) } } for key in try transaction.keys(prefixedBy: LedgerKey.factsPrefix) @@ -150,7 +150,7 @@ extension ExchangeEventSequencer { let ordered = Set(requests).sorted { ($0.key.rawValue, $0.fingerprint) < ($1.key.rawValue, $1.fingerprint) } let instantMilliseconds = ExchangeInstant.millisecondsSinceEpoch(instant) let reserved = try storage.transaction { transaction in - var reserving = ReserveTransaction(transaction: transaction, current: current, instantMilliseconds: instantMilliseconds) + var reserving = ReserveCall(transaction: transaction, current: current, instantMilliseconds: instantMilliseconds) return try reserving.reserve(ordered) } holds.acquire(reserved.values.map(\.handle)) diff --git a/Sources/GroveFHIRContract/ExchangeIdentity.swift b/Sources/GroveFHIRContract/ExchangeIdentity.swift index 55d709d28..2a8d66838 100644 --- a/Sources/GroveFHIRContract/ExchangeIdentity.swift +++ b/Sources/GroveFHIRContract/ExchangeIdentity.swift @@ -175,12 +175,14 @@ package enum ExchangeIdentity { components[0] == "v0", OpaqueIdentityScope.isValidKeyID(String(components[1])), (try? EventSequence(String(components[2]))) != nil, - components[3].utf8.count == 43, - components[3].utf8.allSatisfy({ - $0.isASCIIAlphaNumeric || $0 == 0x2D || $0 == 0x5F - }) else { + isUnpaddedBase64URLDigest(components[3]) else { return false } return true } + + /// Whether `text` has the form of a SHA-256 digest in base64url without padding: 43 characters of `[A-Za-z0-9_-]`. + static func isUnpaddedBase64URLDigest(_ text: some StringProtocol) -> Bool { + text.utf8.count == 43 && text.utf8.allSatisfy { $0.isASCIIAlphaNumeric || $0 == 0x2D || $0 == 0x5F } + } } diff --git a/Sources/GroveFHIRContract/LedgerEntryCoding.swift b/Sources/GroveFHIRContract/LedgerEntryCoding.swift index 6916b5c27..80534ae88 100644 --- a/Sources/GroveFHIRContract/LedgerEntryCoding.swift +++ b/Sources/GroveFHIRContract/LedgerEntryCoding.swift @@ -78,14 +78,9 @@ enum LedgerEntryCoding { /// A producer instance: a UUID stating an RFC 4122 version and variant, as every event identifier requires. static func instance(_ text: String) -> UUID? { - guard let uuid = UUID(uuidString: text), (1...5).contains(uuid.uuid.6 >> 4), uuid.uuid.8 >> 6 == 0b10 else { + guard let uuid = UUID(uuidString: text), ExchangeEventIdentifier.statesRFC4122Version(uuid.uuidString.lowercased()) else { return nil } return uuid } - - /// The form of a SHA-256 digest in base64url without padding. - static func isDigest(_ text: String) -> Bool { - text.utf8.count == 43 && text.utf8.allSatisfy { $0.isASCIIAlphaNumeric || $0 == 0x2D || $0 == 0x5F } - } } diff --git a/Sources/GroveHealthKitFHIR/HealthKitAssembly+Records.swift b/Sources/GroveHealthKitFHIR/HealthKitAssembly+Records.swift index 6edef0968..b49d628e6 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitAssembly+Records.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitAssembly+Records.swift @@ -96,10 +96,9 @@ extension HealthKitAssembly { let symptoms = try HealthKitConverter.validatedSymptomSamples(correlatedSymptoms, status: source.symptomsStatus) return try symptoms.map { symptom in guard let request = requestsBySample[symptom.uuid] else { - throw HealthKitConversionError.ecgEvidence(.symptomContextCountMismatch( - symptoms: correlatedSymptoms.count, - contexts: requestsBySample.count - )) + // The positional shape keys every symptom; the keyed shape keys every symptom of a registered type, + // and validation admits only symptom types that are registered. + preconditionFailure("Every validated symptom has a request in both shapes.") } return try convert(symptom, request: request).primary } diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift index e9aaa7869..1cc5bd6ef 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift @@ -45,8 +45,7 @@ extension HealthKitFHIRExporter { /// never reuses an event identifier for other bytes. A custom ``RecordingDevicePolicy`` resolver enters /// by its presence only; its behaviour is not fingerprinted. struct ExportContext: Sendable { - /// The parts every request of this exporter starts with, in order. - let callParts: [String] + /// The length-framed parts every request of this exporter starts with, in order. private let framedCallParts: Data init(producer: ExchangeProducer, repositoryScope: BusinessIdentifier, options: Options, revisions: OutputRevisions) { @@ -61,7 +60,6 @@ extension HealthKitFHIRExporter { for option in options.fingerprintParts { parts += [option.property] + option.parts } - self.callParts = parts self.framedCallParts = Self.framed(parts) } @@ -115,8 +113,9 @@ extension Subject: ExchangeContextFingerprinted { case let .bundled(identifier, patient): let encoder = JSONEncoder() encoder.outputFormatting = [.sortedKeys, .withoutEscapingSlashes] - // A Patient that cannot be encoded cannot be emitted either; a unique part keeps any reservation unreused. - let patientJSON = (try? encoder.encode(patient)).map { String(decoding: $0, as: UTF8.self) } ?? "unencodable:\(UUID())" + // A Patient that cannot be encoded cannot be emitted either, so its events never carry a graph; no JSON + // text equals the constant, so it never matches an encodable Patient's fingerprint. + let patientJSON = (try? encoder.encode(patient)).map { String(decoding: $0, as: UTF8.self) } ?? "unencodable" return ["bundled", identifier.system.rawValue, identifier.value, patientJSON] } } diff --git a/Tests/GroveFHIRTests/ExchangeLedger/CountingStorage.swift b/Tests/GroveFHIRTests/ExchangeLedger/CountingStorage.swift index c54d29a3d..e6f78603b 100644 --- a/Tests/GroveFHIRTests/ExchangeLedger/CountingStorage.swift +++ b/Tests/GroveFHIRTests/ExchangeLedger/CountingStorage.swift @@ -10,7 +10,8 @@ import Foundation import GroveFHIRContract -/// Counts the transactions a storage runs and the reads, writes, removals and listings inside them. +/// Counts the transactions a storage runs and the reads, writes, removals and listings inside them, in total over +/// every key: the cost bounds the tests state are totals. final class CountingStorage: ExchangeEventSequencer.Storage, @unchecked Sendable { // `counts` is guarded by `lock`. struct Counts: Equatable { var transactions = 0 @@ -49,14 +50,6 @@ final class CountingStorage: ExchangeEventSequencer.Storage, @unchecked Sendable private let lock = NSLock() private var counts = Counts() - var snapshot: Counts { - lock.lock() - defer { - lock.unlock() - } - return counts - } - init(_ base: any ExchangeEventSequencer.Storage = ExchangeEventSequencer.InMemoryStorage()) { self.base = base } diff --git a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerPropertyTests.swift b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerPropertyTests.swift index 6c7c81107..c34064808 100644 --- a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerPropertyTests.swift +++ b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerPropertyTests.swift @@ -148,7 +148,7 @@ struct ExchangeLedgerPropertyTests { group.addTask { for _ in 0..<20 { try sequencer.reset() - try await Task.sleep(for: .milliseconds(5)) + try await Task.sleep(nanoseconds: 5_000_000) } } try await group.waitForAll() From 8bda40794ae2cce2dd31e201e5aeb3d30f37248c Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sat, 3 Oct 2026 22:51:51 +0200 Subject: [PATCH 011/220] Validate Stored Instants and Refuse Instants FHIR Cannot State Spec 1.4 has the ledger reader check that a stored reservation instant is one ExchangeInstant can state; the reader did not. A stored instant of Int64.max reached the conversion and surfaced as a dependency refusal (FHIRDateParserError.invalidYear) instead of the typed ledger fault. - EventEntry(decoding:) requires -62_135_596_800_000 <= instant <= 253_402_300_799_999 (0001-01-01T00:00:00Z through 9999-12-31T23:59:59.999Z, now ExchangeInstant.statableMilliseconds) and throws LedgerError.corruptEntry otherwise; reset() recovers, as for every other corrupt entry. - reserve refuses such an instant before it touches the ledger, with the existing ExchangeIdentityError.invalidInstant. Without this the ledger would write an entry its own reader rejects, and a redelivery would end the whole call with corruptEntry. Deviation, needed for consistency: an export or retraction at an unstatable instant (only reachable with a caller-supplied instant, never with .now) now ends the call with that error instead of refusing each record with a dependency failure. - The export and retract docs list what ends a call: an unstatable instant, a LedgerError (reset() recovers), and errors of the storage or of receive. Tests: G14 rows for an instant after year 9999, before year 1 and Int64.max; both bounds read back as valid reservations; reserve at unstatable instants (year 10000, before year 1, infinity) throws and opens no transaction; an export and a retraction at an unstatable instant throw and touch no ledger. Audit ledger: section 2 finding 5 (stored ledger not validated). G1 review items: design minor 2 and correctness minor 5 (PROBE-F), part of design minor 3(c). Output unchanged: GroveHealthKitFHIR macOS suite (goldens and the G17 digest table) and GroveFHIR suite pass. Co-Authored-By: Claude Opus 5.5 --- .../ExchangeEventSequencer+Entries.swift | 1 + .../ExchangeEventSequencer.swift | 12 +++++- .../GroveFHIRContract/ExchangeInstant.swift | 6 ++- .../HealthKitFHIRExporter+Retraction.swift | 5 ++- .../HealthKitFHIRExporter.swift | 11 +++++- .../ExchangeLedgerEntryTests.swift | 34 +++++++++++++++- .../HealthKitFHIRExporterCallTests.swift | 39 +++++++++++++++++++ 7 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterCallTests.swift diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer+Entries.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer+Entries.swift index b1ca9393d..718f40018 100644 --- a/Sources/GroveFHIRContract/ExchangeEventSequencer+Entries.swift +++ b/Sources/GroveFHIRContract/ExchangeEventSequencer+Entries.swift @@ -90,6 +90,7 @@ struct EventEntry: Equatable { let payload = try LedgerEntryCoding.decode(Payload.self, from: value, key: key) guard let instance = LedgerEntryCoding.instance(payload.instance), let sequence = LedgerEntryCoding.positiveInteger(payload.sequence), + ExchangeInstant.statableMilliseconds.contains(payload.instant), ExchangeIdentity.isUnpaddedBase64URLDigest(payload.facts) else { throw ExchangeEventSequencer.LedgerError.corruptEntry(key: key) } diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift index 25eb720cc..0f598010b 100644 --- a/Sources/GroveFHIRContract/ExchangeEventSequencer.swift +++ b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift @@ -59,7 +59,8 @@ public final class ExchangeEventSequencer: Sendable { /// The entry was written by a later layout; it is refused rather than misread. case unsupportedEntryVersion(key: String, version: Int) /// The entry is malformed, out of range, or inconsistent with the ledger, such as a reservation - /// at or above the counter of its own producer instance, or one naming facts the ledger lacks. + /// at or above the counter of its own producer instance, one at an instant no FHIR instant can + /// state, or one naming facts the ledger lacks. case corruptEntry(key: String) } @@ -142,13 +143,20 @@ extension ExchangeEventSequencer { /// a new producer instance. A sequence is never handed out twice. Each returned reservation is held /// for the caller until ``finish(_:released:forgetting:)``. Exporters reach it through /// `ExchangeProducer.reserve(_:at:)`, which passes the facts the producer prepared once. + /// + /// An `instant` no FHIR instant can state (before year 1 or after year 9999) throws + /// `ExchangeIdentityError.invalidInstant` before the ledger is touched, as the ledger would refuse to read + /// it back. func reserve( _ requests: some Collection, at instant: Date, facts current: PreparedFacts ) throws -> [ExchangeEventRequest: ExchangeEventReservation] { - let ordered = Set(requests).sorted { ($0.key.rawValue, $0.fingerprint) < ($1.key.rawValue, $1.fingerprint) } let instantMilliseconds = ExchangeInstant.millisecondsSinceEpoch(instant) + guard ExchangeInstant.statableMilliseconds.contains(instantMilliseconds) else { + throw ExchangeIdentityError.invalidInstant + } + let ordered = Set(requests).sorted { ($0.key.rawValue, $0.fingerprint) < ($1.key.rawValue, $1.fingerprint) } let reserved = try storage.transaction { transaction in var reserving = ReserveCall(transaction: transaction, current: current, instantMilliseconds: instantMilliseconds) return try reserving.reserve(ordered) diff --git a/Sources/GroveFHIRContract/ExchangeInstant.swift b/Sources/GroveFHIRContract/ExchangeInstant.swift index f442c09ae..6439c2b08 100644 --- a/Sources/GroveFHIRContract/ExchangeInstant.swift +++ b/Sources/GroveFHIRContract/ExchangeInstant.swift @@ -27,8 +27,12 @@ package enum ExchangeInstant { /// `Date` counts from 2001-01-01T00:00:00Z; the wire counts from 1970. private static let referenceEpochMilliseconds: Int64 = 978_307_200_000 + /// 0001-01-01T00:00:00Z through 9999-12-31T23:59:59.999Z in milliseconds since 1970: every instant a FHIR + /// instant or dateTime can state. + static let statableMilliseconds: ClosedRange = -62_135_596_800_000...253_402_300_799_999 + /// 0001-01-01T00:00:00Z, the earliest instant a FHIR instant or dateTime can state. - static let earliestStatable = date(millisecondsSinceEpoch: -62_135_596_800_000) + static let earliestStatable = date(millisecondsSinceEpoch: statableMilliseconds.lowerBound) /// The instant as a FHIR `instant` lexeme in UTC. package static func utcLexeme(_ date: Date) -> String { diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift index 7913356fe..e0bcb0b1d 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift @@ -21,8 +21,9 @@ extension HealthKitFHIRExporter { /// /// Every retraction event is reserved in one ledger transaction. Two deletions of one record with /// different bounds are two events. Releasing the receipt also forgets each deleted record's active - /// reservation, which no export will release once the record is gone. Errors from the sequencer's - /// storage and from `receive` end the call. + /// reservation, which no export will release once the record is gone. The call ends early for the + /// same reasons as ``export(_:at:receive:)``: an unstatable `instant`, a `LedgerError` (recovered by + /// `ExchangeEventSequencer.reset()`), and errors of the ledger's storage or of `receive`. public func retract( _ deletions: some Collection, at instant: Date = .now, diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift index ded1ea75b..f8e518573 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift @@ -69,8 +69,15 @@ public final class HealthKitFHIRExporter: Sendable { } /// Converts samples in input order, calling `receive` once per produced graph or refusal as soon as - /// it is ready. Only the sequencer's storage and `receive` itself can end the call early; their - /// errors are rethrown unchanged, and the reservations stay for the redelivery. + /// it is ready. + /// + /// A record that cannot be converted is refused in place; only these end the call: + /// - an `instant` no FHIR instant can state (before year 1 or after year 9999) throws + /// `ExchangeIdentityError.invalidInstant` before the ledger is touched; + /// - the producer's ledger throws `ExchangeEventSequencer.LedgerError` when a stored entry is corrupt or + /// from a later layout, and `ExchangeEventSequencer.reset()` always recovers; + /// - errors of the ledger's storage and of `receive` are rethrown unchanged, and the reservations made + /// stay for the redelivery. public func export( _ samples: Samples, at instant: Date = .now, diff --git a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerEntryTests.swift b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerEntryTests.swift index c107b77cd..992af4abf 100644 --- a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerEntryTests.swift +++ b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerEntryTests.swift @@ -25,6 +25,9 @@ struct CorruptLedger: Sendable, CustomTestStringConvertible { event: #"{"facts":"","fingerprint":"x","instance":"\#(ExchangeLedgerEntryTests.instance)","instant":1,"sequence":"1"}"# ), CorruptLedger(name: "later version", event: ExchangeLedgerEntryTests.event(version: 2)), + CorruptLedger(name: "instant after year 9999", event: ExchangeLedgerEntryTests.event(instant: 253_402_300_800_000)), + CorruptLedger(name: "instant before year 1", event: ExchangeLedgerEntryTests.event(instant: -62_135_596_800_001)), + CorruptLedger(name: "largest instant", event: ExchangeLedgerEntryTests.event(instant: .max)), CorruptLedger( name: "counter zero", event: ExchangeLedgerEntryTests.event(), @@ -67,8 +70,13 @@ struct ExchangeLedgerEntryTests { return storage } - fileprivate static func event(instance: String = Self.instance, sequence: String = "5", version: Int = 1) -> String { - #"{"facts":"","fingerprint":"context-a","instance":"\#(instance)","instant":1791023400251,"sequence":"\#(sequence)","v":\#(version)}"# + fileprivate static func event( + instance: String = Self.instance, + sequence: String = "5", + instant: Int64 = LedgerFixtures.instantMilliseconds, + version: Int = 1 + ) -> String { + #"{"facts":"","fingerprint":"context-a","instance":"\#(instance)","instant":\#(instant),"sequence":"\#(sequence)","v":\#(version)}"# } @Test("G18: facts with several studies, a versioned canonical and absent host fields decode to themselves") @@ -183,6 +191,28 @@ struct ExchangeLedgerEntryTests { } } + @Test("G14: stored instants at the bounds of what FHIR can state are valid", arguments: [-62_135_596_800_000, 253_402_300_799_999] as [Int64]) + func instantsAtTheBoundsAreValid(_ milliseconds: Int64) throws { + let storage = try Self.seededLedger(event: Self.event(instant: milliseconds)) + let request = Fixtures.request("a") + let reservation = try #require(try Fixtures.sequencer(storage).reserve([request], at: Fixtures.instant, facts: Fixtures.facts())[request]) + #expect(reservation.sequence.rawValue == "5") + #expect(ExchangeInstant.millisecondsSinceEpoch(reservation.instant) == milliseconds) + } + + @Test("An instant FHIR cannot state is refused before the ledger is touched", arguments: [ + Date(timeIntervalSince1970: 253_402_300_800), + Date(timeIntervalSince1970: -62_135_596_800.001), + Date(timeIntervalSinceReferenceDate: .infinity) + ]) + func unstatableInstantsAreRefused(_ instant: Date) throws { + let storage = CountingStorage() + #expect(throws: ExchangeIdentityError.invalidInstant) { + try Fixtures.sequencer(storage).reserve([Fixtures.request("a")], at: instant, facts: Fixtures.facts()) + } + #expect(storage.takeCounts().transactions == 0) + } + @Test("A reservation under a retired instance stays valid; an overflowing counter mints a new instance") func counterOverflowRotatesTheInstance() throws { let storage = try Self.seededLedger( diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterCallTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterCallTests.swift new file mode 100644 index 000000000..a2605a15b --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterCallTests.swift @@ -0,0 +1,39 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +@testable import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit +import Testing + + +/// One call's ledger budget, its early exits, and what its receipt keeps. +@Suite +struct HealthKitFHIRExporterCallTests { + private typealias Fixtures = ExporterFixtures + + @Test("An instant FHIR cannot state ends an export or retraction before the ledger is touched") + func unstatableInstantEndsTheCall() throws { + let storage = LedgerCountingStorage() + let exporter = try Fixtures.exporter(sequencer: ExchangeEventSequencer(storage: storage)) + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0xC5)) + let afterYear9999 = Date(timeIntervalSince1970: 253_402_300_800) + #expect(throws: ExchangeIdentityError.invalidInstant) { + try exporter.export([sample], at: afterYear9999) { _ in } + } + #expect(throws: ExchangeIdentityError.invalidInstant) { + try exporter.retract([Fixtures.deletion(0xC5)], at: afterYear9999) { _ in } + } + #expect(storage.take() == (transactions: 0, writes: 0)) + } +} + +#endif From b53930c48f144e9bcc721cca005c118f85bf63bd Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sat, 3 Oct 2026 22:55:26 +0200 Subject: [PATCH 012/220] Keep a Reservation That a Concurrent Reserve Is About to Reuse A narrow window let a release remove a reservation another call had just reused: the last holder's finish ended its hold, then opened its removal transaction; a reserve of the same key that committed in between reused the stored reservation and took a hold, and the removal then deleted it under that holder. The holder's redelivery became a new event: a duplicate, never a reuse, but avoidable. - HoldRegistry also tracks the reserves in flight, per event key of one ledger. reserve registers its keys before its transaction and, after it, turns them into holds in one locked step (or just drops them when the transaction did not commit), so a reservation it may reuse is never seen unused in between. - finish checks, inside its removing transaction, that no live call holds the exact handle and no reserve of its key is in flight on the same ledger before removing it. A reserve that registered before the check keeps the reservation; one that registers later starts its transaction after the removal, as a storage runs one process's transactions one at a time (every backend in the article's table does). The registry lock is taken inside the transaction only briefly and never held across I/O. - Holds stay keyed by handle, which includes the producer instance and so is unique across ledgers. Keys in flight are scoped to the ledger: ExchangeEventSequencer identifies it by its storage object (so sequencers over one storage share it), or by itself for a storage that is not a class instance. Scoping by key alone would let any ledger in the process (another participant's, or a parallel test's) that reserves the same record keep this ledger's reservation. - The test-only HoldRegistry.count and isEmpty are replaced by mayBeReused(_:in:), which finish needs; the tests that read them now assert per handle, including that a failed reserve leaves no key in flight. - The storage article's holds section states the in-flight rule and its premise. Tests (G9f, GroveFHIRTests): the review's PROBE-G as a test, where a reserve commits between the last holder's end and its removal transaction; the in-flight case, where the release runs while the reserve waits for its transaction; and a reserve of the same key in flight on another storage, which keeps nothing. Verified by mutating and running the suite: without the check in finish the first two fail, registering keys only after the commit fails the in-flight one, and scoping keys without their ledger fails the other-storage one. G1 review items: correctness minor 7 (PROBE-G), design minor 5 (HoldRegistry count/isEmpty). Audit ledger: section 2 finding 3 (release ownership). Output unchanged: GroveHealthKitFHIR macOS suite (goldens and the G17 digest table) and GroveFHIR suite pass. Co-Authored-By: Claude Opus 5.5 --- .../ExchangeEventSequencer+Holds.swift | 58 +++++--- .../ExchangeEventSequencer.swift | 34 ++++- .../ExchangeLedgerStorage.md | 1 + .../ExchangeEventHoldRaceTests.swift | 131 ++++++++++++++++++ .../ExchangeEventHoldTests.swift | 4 +- .../ExchangeLedgerEntryTests.swift | 6 +- .../ExchangeLedger/LedgerFixtures.swift | 5 + 7 files changed, 212 insertions(+), 27 deletions(-) create mode 100644 Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldRaceTests.swift diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer+Holds.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer+Holds.swift index d9b776c3c..4b48812f2 100644 --- a/Sources/GroveFHIRContract/ExchangeEventSequencer+Holds.swift +++ b/Sources/GroveFHIRContract/ExchangeEventSequencer+Holds.swift @@ -9,45 +9,53 @@ import Foundation -/// Which reservations the live calls of this process still hold, and whether any holder released one. +/// Which reservations the live calls of this process still hold, whether any holder released one, and which keys +/// of which ledger a reserve is in flight for. /// /// The ledger's entries hold no per-call state: a reservation is removed when the last live holder in this /// process finishes and any holder released it, so overlapping exports of one record never remove each -/// other's reservation, and a call that throws leaves its reservations for the redelivery. Handles include -/// the producer instance, which every ledger mints for itself, so one registry serves every storage. -/// Holds do not span processes; the lock is never held across I/O. -final class HoldRegistry: @unchecked Sendable { // `holds` is guarded by `lock`. +/// other's reservation, and a call that throws leaves its reservations for the redelivery. A reserve registers +/// its keys before its transaction and turns them into holds in one step after it, so a reservation it may reuse +/// is never seen unused in between. Handles include the producer instance, which every ledger mints for itself, +/// so holds need no ledger; keys in flight are scoped to their ledger. One registry serves every storage. Holds +/// do not span processes; the lock is never held across I/O. +final class HoldRegistry: @unchecked Sendable { // `holds` and `reserving` are guarded by `lock`. private struct Hold { var live: Int var released: Bool } + /// One event key of one ledger. + private struct LedgerEventKey: Hashable { + let ledger: ObjectIdentifier + let key: ExchangeEventKey + } + /// The registry every sequencer of this process shares. static let shared = HoldRegistry() private let lock = NSLock() private var holds: [ExchangeEventReservation.Handle: Hold] = [:] + private var reserving: [LedgerEventKey: Int] = [:] - /// The number of reservations some live call holds. - var count: Int { + /// Marks a reserve of `keys` in `ledger` as in flight; called before its transaction. + func beginReserving(_ keys: some Sequence, in ledger: ObjectIdentifier) { lock.lock() defer { lock.unlock() } - return holds.count - } - - /// Whether no live call holds any reservation. - var isEmpty: Bool { - lock.lock() - defer { - lock.unlock() + for key in keys { + reserving[LedgerEventKey(ledger: ledger, key: key), default: 0] += 1 } - return holds.isEmpty } - /// Takes one hold per handle; called only after the reserving transaction committed. - func acquire(_ handles: some Sequence) { + /// Ends a reserve begun for `keys` in `ledger` and takes one hold per handle it returned, in one step; `handles` + /// is empty when the reserving transaction did not commit. + func endReserving( + _ keys: some Sequence, + in ledger: ObjectIdentifier, + acquiring handles: some Sequence + ) { lock.lock() defer { lock.unlock() @@ -55,6 +63,11 @@ final class HoldRegistry: @unchecked Sendable { // `holds` is guarded by `lock`. for handle in handles { holds[handle, default: Hold(live: 0, released: false)].live += 1 } + for key in keys { + let scoped = LedgerEventKey(ledger: ledger, key: key) + let remaining = (reserving[scoped] ?? 1) - 1 + reserving[scoped] = remaining > 0 ? remaining : nil + } } /// Ends one hold per handle and returns the handles whose last live holder just finished and that some @@ -80,4 +93,13 @@ final class HoldRegistry: @unchecked Sendable { // `holds` is guarded by `lock`. } return removable } + + /// Whether a live call holds `handle`, or a reserve of its key in `ledger` is in flight and may reuse it. + func mayBeReused(_ handle: ExchangeEventReservation.Handle, in ledger: ObjectIdentifier) -> Bool { + lock.lock() + defer { + lock.unlock() + } + return holds[handle] != nil || reserving[LedgerEventKey(ledger: ledger, key: handle.key)] != nil + } } diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift index 0f598010b..a24520334 100644 --- a/Sources/GroveFHIRContract/ExchangeEventSequencer.swift +++ b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift @@ -9,6 +9,10 @@ public import Foundation +/// The identity of a ledger whose storage is not a class instance. +private final class LedgerIdentity: Sendable {} + + /// The exchange-event ledger of one installation: it hands out event sequences and keeps what each /// event is rebuilt from until the caller releases it. /// @@ -65,8 +69,13 @@ public final class ExchangeEventSequencer: Sendable { } let storage: any Storage - /// Which reservations live calls in this process still hold. + /// Which reservations live calls in this process still hold, and which keys a reserve is in flight for. let holds: HoldRegistry + /// The ledger in ``holds``: the storage object, so sequencers over one storage share their reserves in flight. + /// A storage that is not a class instance is identified by this sequencer alone. + let ledger: ObjectIdentifier + /// Keeps the identity of a value-type storage's ledger alive as long as this sequencer. + private let identity: LedgerIdentity /// Creates a sequencer over the application's storage. /// @@ -76,8 +85,11 @@ public final class ExchangeEventSequencer: Sendable { } init(storage: any Storage, holds: HoldRegistry) { + let identity = LedgerIdentity() self.storage = storage self.holds = holds + self.identity = identity + self.ledger = type(of: storage) is AnyClass ? ObjectIdentifier(storage as AnyObject) : ObjectIdentifier(identity) } /// A sequencer over a fresh ``InMemoryStorage``, for tests, previews and single-process tools. @@ -157,11 +169,19 @@ extension ExchangeEventSequencer { throw ExchangeIdentityError.invalidInstant } let ordered = Set(requests).sorted { ($0.key.rawValue, $0.fingerprint) < ($1.key.rawValue, $1.fingerprint) } + let keys = Set(ordered.map(\.key)) + // In flight from before the transaction until its holds are taken, so no release removes a reservation + // this call may be reusing in between. + holds.beginReserving(keys, in: ledger) + var acquired: [ExchangeEventReservation.Handle] = [] + defer { + holds.endReserving(keys, in: ledger, acquiring: acquired) + } let reserved = try storage.transaction { transaction in var reserving = ReserveCall(transaction: transaction, current: current, instantMilliseconds: instantMilliseconds) return try reserving.reserve(ordered) } - holds.acquire(reserved.values.map(\.handle)) + acquired = reserved.values.map(\.handle) return reserved } @@ -169,8 +189,10 @@ extension ExchangeEventSequencer { /// /// `released` says the caller's output is durably handed off. When the last live holder of a /// reservation in this process finishes and any holder released it, the reservation is removed, but - /// only while the key still holds exactly that reservation. `keys` are forgotten whatever they hold, - /// and only when `released` is true. Opens one transaction when anything is to be removed, none otherwise. + /// only while the key still holds exactly that reservation and, checked inside the removing transaction, + /// no live call holds it and no reserve of its key is in flight on this storage. `keys` are forgotten + /// whatever they hold, and only when `released` is true. Opens one transaction when anything is to be + /// removed, none otherwise. package func finish( _ held: [ExchangeEventReservation.Handle], released: Bool, @@ -182,7 +204,9 @@ extension ExchangeEventSequencer { return } try storage.transaction { transaction in - for handle in removable { + // A reserve that registered before this check may reuse the reservation, so it stays; one that registers + // later starts its transaction after this one, as a storage runs a process's transactions one at a time. + for handle in removable where !holds.mayBeReused(handle, in: ledger) { let key = LedgerKey.event(handle.key) guard let value = try transaction.read(key) else { continue diff --git a/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md b/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md index c69839aa1..f2c51a3a2 100644 --- a/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md +++ b/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md @@ -74,6 +74,7 @@ Both the cutoff and the stored instants are on the caller's clock, so choose one The entries hold no per-call state. Live calls are tracked in process memory: when the last call in the process that holds an event finishes and any of them released it, the event's reservation is removed, and otherwise it stays for the redelivery. +A reserve registers its keys before its transaction, and the removing transaction checks them, so a release never removes a reservation that a call on the same storage object in the same process is about to reuse; this relies on the storage running one process's transactions one at a time, as every backend above does. A release only ever removes the exact reservation its call made, never a successor's or one from before a reset. Holds do not span processes; when two live processes share one storage, a release in one can remove a reservation the other still holds, and the other's redelivery then becomes a new event, a duplicate and never a reuse. diff --git a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldRaceTests.swift b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldRaceTests.swift new file mode 100644 index 000000000..66313faf2 --- /dev/null +++ b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldRaceTests.swift @@ -0,0 +1,131 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +import Dispatch +import Foundation +@testable import GroveFHIRContract +import Testing + + +/// Blocks the next transaction until signalled, so a test can run another call before it. +private final class GateStorage: ExchangeEventSequencer.Storage, @unchecked Sendable { // `gateNext` is guarded by `lock`. + let base = ExchangeEventSequencer.InMemoryStorage() + /// Signalled when the gated transaction is reached. + let entered = DispatchSemaphore(value: 0) + /// Lets the gated transaction run. + let proceed = DispatchSemaphore(value: 0) + private let lock = NSLock() + private var gateNext = false + + func gate() { + lock.lock() + defer { + lock.unlock() + } + gateNext = true + } + + func transaction(_ body: (any ExchangeEventSequencer.Transaction) throws -> R) throws -> R { + lock.lock() + let gated = gateNext + gateNext = false + lock.unlock() + if gated { + entered.signal() + proceed.wait() + } + return try base.transaction(body) + } +} + + +/// What a call on another thread reserved, empty when it threw; read only after that thread signalled. +private final class ReservedBox: @unchecked Sendable { + var reserved: [ExchangeEventRequest: ExchangeEventReservation] = [:] +} + + +/// A release racing a reserve of the same key never removes a reservation the reserve reuses. +@Suite +struct ExchangeEventHoldRaceTests { + private typealias Fixtures = LedgerFixtures + + @Test("G9f: a reserve that commits between the last holder's end and its removal keeps the reservation") + func reserveBeforeTheRemovalTransaction() throws { + let storage = GateStorage() + let sequencer = Fixtures.sequencer(storage) + let request = Fixtures.request("race") + let facts = try Fixtures.facts() + let first = try sequencer.reserve([request], at: Fixtures.instant, facts: facts) + let handles = first.values.map(\.handle) + let finished = DispatchSemaphore(value: 0) + storage.gate() + Thread { + try? sequencer.finish(handles, released: true, forgetting: []) + finished.signal() + }.start() + // The last holder has ended its hold and waits to open its removal transaction; another call reserves now. + storage.entered.wait() + let second = try sequencer.reserve([request], at: Fixtures.instant, facts: facts) + storage.proceed.signal() + finished.wait() + #expect(second == first) + #expect(try Fixtures.stored(LedgerKey.event(request.key), in: storage.base) != nil, "the second call still holds it") + let redelivery = try sequencer.reserve([request], at: Fixtures.instant, facts: facts) + #expect(redelivery == first, "its redelivery is an exact retry") + try sequencer.finish(second.values.map(\.handle) + redelivery.values.map(\.handle), released: true, forgetting: []) + #expect(try Fixtures.stored(LedgerKey.event(request.key), in: storage.base) == nil) + #expect(!Fixtures.mayBeReused(first[request]?.handle, by: sequencer)) + } + + @Test("G9f: a release while a reserve of the key is in flight keeps the reservation for that reserve") + func releaseWhileAReserveIsInFlight() throws { + let storage = GateStorage() + let sequencer = Fixtures.sequencer(storage) + let request = Fixtures.request("race") + let facts = try Fixtures.facts() + let first = try sequencer.reserve([request], at: Fixtures.instant, facts: facts) + let box = ReservedBox() + let reserved = DispatchSemaphore(value: 0) + storage.gate() + Thread { + box.reserved = (try? sequencer.reserve([request], at: Fixtures.instant, facts: facts)) ?? [:] + reserved.signal() + }.start() + // The second call registered its reserve and waits to open its transaction; the last holder releases now. + storage.entered.wait() + try sequencer.finish(first.values.map(\.handle), released: true, forgetting: []) + #expect(try Fixtures.stored(LedgerKey.event(request.key), in: storage.base) != nil) + storage.proceed.signal() + reserved.wait() + #expect(box.reserved == first, "the second call reused the reservation") + } + + @Test("G9f: a reserve in flight on another storage does not keep this ledger's reservation") + func reserveInFlightElsewhereKeepsNothing() throws { + let registry = HoldRegistry() + let other = GateStorage() + let request = Fixtures.request("race") + let facts = try Fixtures.facts() + let reserved = DispatchSemaphore(value: 0) + other.gate() + Thread { + _ = try? ExchangeEventSequencer(storage: other, holds: registry).reserve([request], at: Fixtures.instant, facts: facts) + reserved.signal() + }.start() + // The same key is in flight on another ledger while this one releases it. + other.entered.wait() + let storage = ExchangeEventSequencer.InMemoryStorage() + let sequencer = ExchangeEventSequencer(storage: storage, holds: registry) + let first = try sequencer.reserve([request], at: Fixtures.instant, facts: facts) + try sequencer.finish(first.values.map(\.handle), released: true, forgetting: []) + #expect(try Fixtures.stored(LedgerKey.event(request.key), in: storage) == nil) + other.proceed.signal() + reserved.wait() + } +} diff --git a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldTests.swift b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldTests.swift index feda3f1df..31918cc0a 100644 --- a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldTests.swift +++ b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldTests.swift @@ -32,7 +32,7 @@ struct ExchangeEventHoldTests { #expect(again == first) try sequencer.finish(again.values.map(\.handle), released: true, forgetting: []) #expect(try !Self.isReserved(request, in: storage)) - #expect(sequencer.holds.isEmpty) + #expect(!Fixtures.mayBeReused(again[request]?.handle, by: sequencer)) } @Test("G8: after a crash between reserve and release, the next process reuses and removes the reservation") @@ -74,7 +74,7 @@ struct ExchangeEventHoldTests { try sequencer.finish(winner.values.map(\.handle), released: true, forgetting: []) try sequencer.finish(loser.values.map(\.handle), released: false, forgetting: []) #expect(try !Self.isReserved(request, in: storage)) - #expect(sequencer.holds.isEmpty) + #expect(!Fixtures.mayBeReused(winner[request]?.handle, by: sequencer)) } @Test("G10: a handle from before a reset releases nothing, and a replaced reservation is not removed") diff --git a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerEntryTests.swift b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerEntryTests.swift index 992af4abf..eddbb7780 100644 --- a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerEntryTests.swift +++ b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerEntryTests.swift @@ -231,7 +231,7 @@ struct ExchangeLedgerEntryTests { func failuresAreAtomic() throws { let storage = FaultyStorage() let sequencer = Fixtures.sequencer(storage) - _ = try sequencer.reserve([Fixtures.request("a")], at: Fixtures.instant, facts: Fixtures.facts()) + let first = try sequencer.reserve([Fixtures.request("a")], at: Fixtures.instant, facts: Fixtures.facts()) let before = try Fixtures.keys("", in: storage.base) let requests = ["b", "c", "d"].map { Fixtures.request($0) } for write in 1...4 { @@ -247,7 +247,9 @@ struct ExchangeLedgerEntryTests { } storage.failAtCommit(false) #expect(try Fixtures.keys("", in: storage.base) == before) - #expect(sequencer.holds.count == 1, "only the first call's hold") + #expect(Fixtures.mayBeReused(first.values.first?.handle, by: sequencer), "the first call still holds its reservation") + let unheld = requests.map { ExchangeEventReservation.Handle(key: $0.key, instance: UUID(), sequence: 1) } + #expect(!unheld.contains { Fixtures.mayBeReused($0, by: sequencer) }, "a failed reserve leaves no key in flight") let retried = try sequencer.reserve(requests, at: Fixtures.instant, facts: Fixtures.facts(build: "200")) #expect(Set(retried.values.map(\.sequence.rawValue)) == ["2", "3", "4"]) } diff --git a/Tests/GroveFHIRTests/ExchangeLedger/LedgerFixtures.swift b/Tests/GroveFHIRTests/ExchangeLedger/LedgerFixtures.swift index fafb3dd93..a67397e9a 100644 --- a/Tests/GroveFHIRTests/ExchangeLedger/LedgerFixtures.swift +++ b/Tests/GroveFHIRTests/ExchangeLedger/LedgerFixtures.swift @@ -63,6 +63,11 @@ enum LedgerFixtures { ExchangeEventSequencer(storage: storage, holds: HoldRegistry()) } + /// Whether a live call on `sequencer` holds `handle`, or a reserve of its key is in flight on its storage. + static func mayBeReused(_ handle: ExchangeEventReservation.Handle?, by sequencer: ExchangeEventSequencer) -> Bool { + handle.map { sequencer.holds.mayBeReused($0, in: sequencer.ledger) } ?? false + } + /// The raw value stored under `key`. static func stored(_ key: String, in storage: any ExchangeEventSequencer.Storage) throws -> Data? { try storage.transaction { try $0.read(key) } From c8431f93f22eb21736f2558a8251a901714813f9 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sat, 3 Oct 2026 22:59:14 +0200 Subject: [PATCH 013/220] Correct the Ledger, Receipt and Recipe Docs - ExchangeLedgerStorage: the keychain's C2 cell again says that the commit surviving power loss is Apple's guarantee and unverified here, as the design states it ([unverified] in spec 1.3); the article had dropped the caveat. - ExchangeLedgerStorage and the Receipt doc no longer claim a release opens no transaction "when nothing was reserved": a retraction's receipt forgets each deleted record's active reservation, so its release runs one transaction whenever it names a deletion, even when every deletion was of a type with nothing to retract (PROBE-C; the behaviour is per spec 1.5.3 and is kept). An export's receipt runs none when it reserved nothing or another call still holds its events. - ExchangeLedgerStorage's "a release only ever removes the exact reservation its call made" now names its one exception, a retraction's forgetting. - The GroveFHIRContract article again tells adapters that convert under an ExchangeEventContext the caller builds (GroveSensorKitFHIR today) to persist the producer instance and durably advance the next sequence before emitting, in the event-identifier section and the what-to-persist table; the ledger recipe had dropped that guidance. The export and retract docs naming LedgerError and the reset() recovery landed with the instant validation, which rewrote the same sentences; the ExchangeProducer init doc landed with the prepared facts. Audit ledger: section 2 finding 11 (contract article), section 3 findings 5 and 8 (receipt cost and docs). G1 review items: design minor 3(a), 3(b), 3(d); correctness minor 6. Output unchanged: documentation and doc comments only. Co-Authored-By: Claude Opus 5.5 --- .../GroveFHIRContract.docc/ExchangeLedgerStorage.md | 7 +++++-- .../GroveFHIRContract.docc/GroveFHIRContract.md | 2 ++ .../GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift | 5 +++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md b/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md index f2c51a3a2..c2e8c49de 100644 --- a/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md +++ b/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md @@ -55,14 +55,16 @@ What Grove promises a storage in return: | --- | --- | --- | --- | --- | --- | | In memory (``ExchangeEventSequencer/InMemoryStorage``) | Writes are buffered and applied when the body returns. | The storage lives as long as its process; exiting loses every entry, which C4 allows. | One lock per transaction. | It cannot be restored or copied. | Values are stored as given. | | One file, rewritten atomically | Mutate a copy, write a temporary file in the same directory, rename it over the original. | `F_FULLFSYNC` on the temporary file before the rename, then `fsync` the directory. | A process lock plus `flock` on a sibling lock file that is never replaced. | Exclude the directory from backup; never sync it. | A binary property list `[String: Data]`. | -| Keychain (small or pruned ledgers) | The whole map is one item, replaced in one call. | The keychain commits before the call returns. | A process lock, plus a lock file for app extensions sharing the item. | A this-device-only, non-synchronizable item, guarded by a token also kept in a non-backed-up file; a missing or differing token presents an empty map. | A binary property list `[String: Data]`. | +| Keychain (small or pruned ledgers) | The whole map is one item, replaced in one call. | The keychain commits the item before the call returns; that the commit survives power loss is Apple's guarantee, not verified here. | A process lock, plus a lock file for app extensions sharing the item. | A this-device-only, non-synchronizable item, guarded by a token also kept in a non-backed-up file; a missing or differing token presents an empty map. | A binary property list `[String: Data]`. | | Core Data | A private context per transaction and one save, discarded on a throw. | Fully synchronous commits with a device-cache flush. | One process lock; an error merge policy fails a conflicting save, and the body runs again. | Exclude the store from backup; no CloudKit mirroring. | A string key with a uniqueness constraint and a binary value. | | SQL database | One transaction per call over a relation with a unique key and a binary value. | The engine's fully durable commit, including the device-cache flush. | Serializable isolation, or a transaction that takes the write lock first. | Exclude the database from backup; never restore it from replicas or snapshots. | A key column with binary collation and a binary value column. | ## Cost and retention An export or retraction is one transaction that touches only the entries of its own event keys, the `producer` entry and each distinct facts entry once; a reservation that is reused writes nothing. -Releasing a receipt is at most one more transaction, and none when it reserved nothing. +Releasing a receipt is at most one more transaction. +An export's receipt runs none when it reserved nothing, or when another call in the process still holds its events. +A retraction's receipt runs one whenever it names a deletion, even of a type with nothing to retract, because it also forgets each deleted record's active reservation. Backends that store entries individually (in memory, Core Data, SQL) therefore cost what a call touches, whatever the ledger's size. The single-file and keychain backends rewrite the whole map on every transaction and suit small ledgers, or ledgers you prune. @@ -76,6 +78,7 @@ The entries hold no per-call state. Live calls are tracked in process memory: when the last call in the process that holds an event finishes and any of them released it, the event's reservation is removed, and otherwise it stays for the redelivery. A reserve registers its keys before its transaction, and the removing transaction checks them, so a release never removes a reservation that a call on the same storage object in the same process is about to reuse; this relies on the storage running one process's transactions one at a time, as every backend above does. A release only ever removes the exact reservation its call made, never a successor's or one from before a reset. +The one exception is a retraction's receipt: on release it forgets each deleted record's active reservation, whatever that reservation is, because no export will release it once the record is gone. Holds do not span processes; when two live processes share one storage, a release in one can remove a reservation the other still holds, and the other's redelivery then becomes a new event, a duplicate and never a reuse. ## Topics diff --git a/Sources/GroveFHIRContract/GroveFHIRContract.docc/GroveFHIRContract.md b/Sources/GroveFHIRContract/GroveFHIRContract.docc/GroveFHIRContract.md index f6fe9bdb8..9a3dd9f29 100644 --- a/Sources/GroveFHIRContract/GroveFHIRContract.docc/GroveFHIRContract.md +++ b/Sources/GroveFHIRContract/GroveFHIRContract.docc/GroveFHIRContract.md @@ -52,6 +52,7 @@ Every export is an exchange event, and every event is immutable. An ``ExchangeEventIdentifier`` is your producer instance UUID plus a monotonic ``EventSequence``. A retry resends the same bytes under the same identifier; a new revision of the record gets a new sequence. An ``ExchangeProducer``'s ``ExchangeEventSequencer`` mints both and keeps them, with what each event states, in a ledger your app stores; says what that storage must guarantee. +An adapter that converts under an ``ExchangeEventContext`` you build yourself, such as `GroveSensorKitFHIR`, does not use the ledger: persist the producer instance once and durably advance the next sequence before you emit. ### The repository scope @@ -104,6 +105,7 @@ What to persist, and why: | Value | Why | | --- | --- | | The ledger | It numbers every event and freezes what each one states until the receipt is released; a reused sequence under different content is a conflict the receiver cannot resolve. | +| The producer instance and the next sequence, for an adapter that takes an ``ExchangeEventContext`` | The ledger does not number those events; advance the sequence durably before you emit, and never reuse one for different content. | | The key id and epoch, beside the key | They select the systems every identity is minted under. | > Important: Never restore the ledger from a backup or copy it to another installation, and never change the key or the epoch without deriving new systems. diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift index b40bb90e4..71348f86f 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift @@ -96,8 +96,9 @@ extension HealthKitFHIRExporter { /// Call ``release()`` once every produced graph is durably stored AND the source cursor (HealthKit anchor, /// bulk-export checkpoint) is committed. Until then an exact redelivery of the same records reproduces the /// same events, byte for byte. Releasing is idempotent, also across copies of this reference, and makes - /// one ledger transaction at most: none when nothing was reserved, or while another call in this process - /// still holds the same events. + /// one ledger transaction at most. An export's receipt makes none when nothing was reserved, or while + /// another call in this process still holds the same events. A retraction's receipt makes one whenever it + /// names a deletion, as it also forgets each deleted record's active reservation. /// /// A receipt dropped unreleased (the call threw, or its commit action was discarded) leaves its /// reservations for the redelivery. When another call in this process released the same event, the last From b17f10d0dfe500e98bb58eedd1842d5520138059 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sat, 3 Oct 2026 23:09:44 +0200 Subject: [PATCH 014/220] Close the Ledger Review's Surviving Mutations With Discriminating Tests The G1 review re-applied 42 mutations to ffec7fbc; 11 survived the suite. Each now fails it. - G3 computes every context's request fingerprint directly (exporter.context.request(for:).fingerprint) and requires the base context and its 30 perturbations to be pairwise distinct, naming any colliding pair. It shared one ledger without releases before, so each perturbation was only compared with the previous one and a dropped part that followed another perturbation passed. New perturbations: the identity scope's key id (same systems, so only ledgerFingerprint can tell it) and the bundled Patient's content (same pseudonym). A second test ties the direct fingerprints to the export path: the stored reservation carries the base context's fingerprint, an equal context reuses the event and a perturbed one does not. - G3b compares, for the defaults and every option perturbation, each stored property's own value parts (through Mirror) with the parts fingerprintParts pairs with its name, so a value paired with the wrong name fails, not only a missing name. - G2 for gatewayForOwnWrites: a self-written sample (revision 100) under build 100, redelivered before release by a producer rebuilt with build 110, is the same event and byte-identical; the comparison uses the frozen build. After release the new event compares with build 110 and states no gateway. - A three-deletion retraction takes one reserve transaction and its release one more. - A retraction with only nothing-to-retract deletions reserves nothing, and its release runs one transaction that forgets the active key (PROBE-C, documenting the behaviour the corrected docs describe). - A released receipt dropped while another call holds the same event leaves the event stored: deinit after release() ends no hold a second time. - Record paths through export(records:): .electrocardiogram (refused by the record path's voltage validation, as the fixture ECG reports no voltage count; its and its symptom's reservations are held until release), .heartbeatSeries and an authorized .workoutRoute (byte-equal to the assembly's graph under the same event), and a route the policy omits, which delivers nothing, keeps the export going and holds its event until release. - E1 on every OS: a duplicated symptom is refused as duplicateSymptomSource, so the keyed ECG path is covered where no unregistered category type exists (before OS 27). Mutation acceptance (each re-applied to the final tree of this series, full GroveHealthKitFHIRTests target on macOS, then reverted; M5b re-expressed for producer.reserve(_:at:), the others with the review's exact texts): | Mutation | Change | Result | Failing tests | | --- | --- | --- | --- | | M2b | gatewayApplication build dropped from the fingerprint | FAIL | G3 pairwise ("gateway build" = "role gatewayApplication") | | M2c | native-identifier type display dropped | FAIL | G3 pairwise ("type display" = "type") | | M2g | repository scope dropped | FAIL | G3 pairwise ("repository scope" = base) | | M2m | legacyBundleID .healthKitUUID fingerprints as none | FAIL | G3 pairwise ("legacyBundleID" = base) | | M2o | udi paired with a constant .omit | FAIL | G3 pairwise ("udi" = base), G3b value pairing | | M2j | bundled Patient JSON dropped | FAIL | G3 pairwise ("bundled Patient content" = "bundled subject") | | M2k | key id dropped from ledgerFingerprint | FAIL | G3 pairwise ("key id" = base) | | M1c | gatewayForOwnWrites compares with the live build | FAIL | G2 gatewayForOwnWrites | | M5b | one reserve transaction per retraction request | FAIL | three-deletion retraction (3 transactions) | | M4b | Receipt.deinit ignores isFinished | FAIL | released receipt dropped while another holds | | ME1a | keyed symptom requests count-checked | FAIL | E1 duplicate symptom, E1 unregistered symptom | G1 review items: design M1; correctness MAJOR 1 and 2, minors 3, 4, 6 (test), 8 and the E1-on-every-OS item. Output unchanged: tests only; GroveHealthKitFHIR macOS suite passes (266 tests, 2 skipped by availability) with every golden byte-identical. Co-Authored-By: Claude Opus 5.5 --- .../HealthKitFHIRExporterCallTests.swift | 75 +++++++++ ...ealthKitFHIRExporterFingerprintTests.swift | 93 +++++++---- .../HealthKitFHIRExporterRecordTests.swift | 153 ++++++++++++++++++ 3 files changed, 291 insertions(+), 30 deletions(-) create mode 100644 Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterRecordTests.swift diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterCallTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterCallTests.swift index a2605a15b..231a4f027 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterCallTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterCallTests.swift @@ -12,6 +12,7 @@ import Foundation @testable import GroveFHIRContract @testable import GroveHealthKitFHIR import HealthKit +import ModelsR4 import Testing @@ -20,6 +21,12 @@ import Testing struct HealthKitFHIRExporterCallTests { private typealias Fixtures = ExporterFixtures + /// Whether the graph's Observation names a gateway Device. + private static func statesGateway(_ export: HealthKitFHIRExporter.Export) -> Bool { + let observation = export.graph?.bundle.entry?.compactMap { $0.resource?.get(if: Observation.self) }.first + return observation?.extension?.contains { $0.url == Canonicals.gatewayDevice } == true + } + @Test("An instant FHIR cannot state ends an export or retraction before the ledger is touched") func unstatableInstantEndsTheCall() throws { let storage = LedgerCountingStorage() @@ -34,6 +41,74 @@ struct HealthKitFHIRExporterCallTests { } #expect(storage.take() == (transactions: 0, writes: 0)) } + + @Test("G2: under gatewayForOwnWrites a redelivery after an app update compares with the frozen build, byte for byte") + func gatewayForOwnWritesComparesTheFrozenBuild() throws { + let sequencer = ExchangeEventSequencer.inMemory() + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0xD0), writer: GoldenFixtures.selfWriter(revisionVersion: "100")) + // The app wrote the sample in build 100 and converts it there; the redelivery runs after an update to build 110. + let exporters = try ["100", "110"].map { build in + try Fixtures.exporter(try Fixtures.producer(application: GoldenFixtures.selfConverter(version: "1.0", build: build), sequencer: sequencer)) { + $0.role = .gatewayForOwnWrites + } + } + let (first, firstReceipt) = try Fixtures.collect(exporters[0], samples: [sample]) + #expect(Self.statesGateway(first[0]), "build 100 wrote the sample, so it mediated it") + let (again, againReceipt) = try Fixtures.collect(exporters[1], samples: [sample]) + #expect(again[0].event == first[0].event) + #expect(again[0].graph?.json == first[0].graph?.json) + firstReceipt.release() + againReceipt.release() + let (renewed, _) = try Fixtures.collect(exporters[1], samples: [sample]) + #expect(renewed[0].event != first[0].event) + #expect(!Self.statesGateway(renewed[0]), "a new event compares with build 110, which did not write the sample") + } + + @Test("A retraction reserves every deletion in one transaction, and its release takes one more") + func retractionTakesOneReserveTransaction() throws { + let storage = LedgerCountingStorage() + let exporter = try Fixtures.exporter(sequencer: ExchangeEventSequencer(storage: storage)) + let (exports, receipt) = try Fixtures.retract(exporter, [Fixtures.deletion(0xD1), Fixtures.deletion(0xD2), Fixtures.deletion(0xD3)]) + #expect(Set(exports.compactMap(\.sequence)) == ["1", "2", "3"]) + #expect(storage.take().transactions == 1) + receipt.release() + #expect(storage.take().transactions == 1) + } + + @Test("A retraction with nothing to retract reserves nothing; its release still forgets the deleted record's active reservation") + func nothingToRetractStillForgets() throws { + let storage = LedgerCountingStorage() + let exporter = try Fixtures.exporter(sequencer: ExchangeEventSequencer(storage: storage)) + let deletion = HealthKitFHIRExporter.Deletion( + uuid: GoldenFixtures.uuid(0xD4), + sourceType: .bloodPressureSystolic, + deletedAfter: nil, + detectedAt: GoldenFixtures.conversionInstant + ) + let (exports, receipt) = try Fixtures.retract(exporter, [deletion]) + guard case .nothingToRetract = exports.first?.outcome else { + Issue.record("expected nothing to retract, got \(String(describing: exports.first?.outcome))") + return + } + #expect(storage.take().transactions == 0) + receipt.release() + #expect(storage.take() == (transactions: 1, writes: 1)) + } + + @Test("A released receipt dropped while another call holds the same event leaves the event to that call") + func releasedReceiptDroppedKeepsTheOtherHold() throws { + let storage = LedgerCountingStorage() + let exporter = try Fixtures.exporter(sequencer: ExchangeEventSequencer(storage: storage)) + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0xD5)) + let key = try #require(ExchangeEventKey.active(sample)) + var released: HealthKitFHIRExporter.Receipt? = try Fixtures.collect(exporter, samples: [sample]).receipt + let (_, holding) = try Fixtures.collect(exporter, samples: [sample]) + released?.release() + released = nil + #expect(try storage.holdsReservation(for: key), "dropping a released receipt ends no hold a second time") + holding.release() + #expect(try !storage.holdsReservation(for: key)) + } } #endif diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFingerprintTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFingerprintTests.swift index 27973d8ec..2faa6b568 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFingerprintTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFingerprintTests.swift @@ -13,6 +13,7 @@ import Foundation @testable import GroveFHIRContract @testable import GroveHealthKitFHIR import HealthKit +import ModelsR4 import Testing @@ -66,49 +67,81 @@ struct HealthKitFHIRExporterFingerprintTests { ] } - @Test("G3: every option, the subject, the repository and identity scopes and each output revision version the event") + /// The base context first, then every perturbation of an option, the subject, a scope or an output revision. @available(*, deprecated, message: "Names the transitional legacy Bundle.id case") - func everyContextInputVersionsTheEvent() throws { - let sequencer = ExchangeEventSequencer.inMemory() - let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(1), device: GoldenFixtures.watch, writer: GoldenFixtures.foreignWriter) + private static func contexts(sequencer: ExchangeEventSequencer) throws -> [(String, HealthKitFHIRExporter)] { let base = try Fixtures.producer(sequencer: sequencer) - var exporters: [(String, HealthKitFHIRExporter)] = try Self.optionPerturbations().map { name, configure in + let systems = Fixtures.base.identityScope.systems + let pseudonym = Fixtures.base.subject.identifier + var patient = Patient() + patient.gender = FHIRPrimitive(AdministrativeGender.female) + func scope(keyID: String = "test", epoch: UInt64 = 1, key: SymmetricKey = Self.key) throws -> OpaqueIdentityScope { + try OpaqueIdentityScope(systems: systems, keyID: keyID, epoch: EventSequence(epoch), key: key) + } + var contexts: [(String, HealthKitFHIRExporter)] = [("base", try Fixtures.exporter(base))] + contexts += try Self.optionPerturbations().map { name, configure in (name, try Fixtures.exporter(base, configure)) } - let systems = Fixtures.base.identityScope.systems - exporters += [ + contexts += [ ("subject", try Fixtures.exporter(try Fixtures.producer(subject: .logical(.test(.patient, "other")), sequencer: sequencer))), - ("bundled subject", try Fixtures.exporter(try Fixtures.producer(subject: .bundled(.test(.patient, "example"), .init()), sequencer: sequencer))), + ("bundled subject", try Fixtures.exporter(try Fixtures.producer(subject: .bundled(pseudonym, Patient()), sequencer: sequencer))), + ("bundled Patient content", try Fixtures.exporter(try Fixtures.producer(subject: .bundled(pseudonym, patient), sequencer: sequencer))), ("repository scope", try Fixtures.exporter(base, repositoryScope: .test(.device, "secondary"))), - ("epoch", try Fixtures.exporter(try Fixtures.producer( - identityScope: OpaqueIdentityScope(systems: systems, keyID: "test", epoch: EventSequence(2), key: Self.key), - sequencer: sequencer - ))), - ("key", try Fixtures.exporter(try Fixtures.producer( - identityScope: OpaqueIdentityScope(systems: systems, keyID: "test", epoch: EventSequence(1), key: SymmetricKey(data: Data(repeating: 7, count: 32))), - sequencer: sequencer - ))), + ("epoch", try Fixtures.exporter(try Fixtures.producer(identityScope: scope(epoch: 2), sequencer: sequencer))), + ("key", try Fixtures.exporter(try Fixtures.producer(identityScope: scope(key: SymmetricKey(data: Data(repeating: 7, count: 32))), sequencer: sequencer))), + ("key id", try Fixtures.exporter(try Fixtures.producer(identityScope: scope(keyID: "other"), sequencer: sequencer))), ("assembler revision", try Fixtures.exporter(base, revisions: .init(assembler: ExchangeGraphAssembler.outputRevision + 1, healthKit: HealthKitAssembly.outputRevision))), ("adapter revision", try Fixtures.exporter(base, revisions: .init(assembler: ExchangeGraphAssembler.outputRevision, healthKit: HealthKitAssembly.outputRevision + 1))) ] - let (original, _) = try Fixtures.collect(try Fixtures.exporter(base), samples: [sample]) - let (unchanged, _) = try Fixtures.collect(try Fixtures.exporter(base), samples: [sample]) - #expect(unchanged[0].event == original[0].event, "an equal context reuses the reservation") - var sequences = [try #require(original[0].sequence)] - for (name, exporter) in exporters { - let (exports, _) = try Fixtures.collect(exporter, samples: [sample]) - let sequence = try #require(exports[0].sequence, "\(name): \(exports[0].outcome)") - #expect(!sequences.contains(sequence), "\(name) reused an event") - sequences.append(sequence) + return contexts + } + + @Test("G3: the base context and every perturbation of an option, the subject, a scope or an output revision fingerprint pairwise apart") + @available(*, deprecated, message: "Names the transitional legacy Bundle.id case") + func everyContextInputVersionsTheEvent() throws { + let contexts = try Self.contexts(sequencer: .inMemory()) + let key = ExchangeEventKey.active(type: .heartRate, uuid: GoldenFixtures.uuid(1)) + let fingerprints = contexts.map { name, exporter in (name, exporter.context.request(for: key).fingerprint) } + for (index, (name, fingerprint)) in fingerprints.enumerated() { + for (earlier, earlierFingerprint) in fingerprints[.. Void = { _ in } + ) throws -> HealthKitConversionContext { + var options = HealthKitConversionOptions() + configure(&options) + let base = Fixtures.base + return HealthKitConversionContext( + event: ExchangeEventContext( + subject: base.subject, + event: try #require(event), + identityScope: base.identityScope, + repositoryScope: base.repositoryScope, + application: base.application, + host: base.host, + conversionInstant: GoldenFixtures.conversionInstant + ), + options: options + ) + } + + private static func exports( + _ records: [HealthKitFHIRExporter.Record], + _ exporter: HealthKitFHIRExporter + ) throws -> (exports: [HealthKitFHIRExporter.Export], receipt: HealthKitFHIRExporter.Receipt) { + var exports: [HealthKitFHIRExporter.Export] = [] + let receipt = try exporter.export(records: records, at: GoldenFixtures.conversionInstant) { exports.append($0) } + return (exports, receipt) + } + + @Test("An ECG record's voltages are validated against its sample, and a refusal holds the ECG's and its symptoms' events") + func electrocardiogramRecord() throws { + let storage = LedgerCountingStorage() + let exporter = try Fixtures.exporter(sequencer: ExchangeEventSequencer(storage: storage)) + // `HKElectrocardiogram.VoltageMeasurement` cannot be built outside HealthKit, and the fixture ECG reports no + // voltage count, so the record path refuses it; the evidence seam (E2) covers the converted ECG. + let (ecg, _) = try GoldenCase.electrocardiogramEvidence(uuid: 0xE0, symptomsPresent: true) + let symptom = try GoldenCase.symptom(uuid: GoldenFixtures.uuid(0xE1)) + let (exports, receipt) = try Self.exports([.electrocardiogram(ecg, voltages: [], symptoms: [symptom])], exporter) + try #require(exports.count == 1) + guard case .refused(let reason) = exports[0].outcome else { + Issue.record("expected a refusal, got \(exports[0].outcome)") + return + } + #expect(reason == .ecgEvidence(.invalidReportedVoltageCount(0))) + #expect(storage.take().transactions == 1) + let keys = try [#require(ExchangeEventKey.active(ecg)), #require(ExchangeEventKey.active(symptom))] + #expect(try keys.allSatisfy { try storage.holdsReservation(for: $0) }) + receipt.release() + #expect(try !keys.contains { try storage.holdsReservation(for: $0) }) + } + + @Test("A heartbeat-series record is the recording document the assembly builds under the exporter's event") + func heartbeatSeriesRecord() throws { + let exporter = try Fixtures.exporter() + let series = try StoredSampleFixtures.seriesSample( + HKHeartbeatSeriesSample.self, + sampleType: HKSeriesType.heartbeat(), + shape: GoldenCase.seriesShape(uuid: 0xE2, duration: 2) + ) + let (exports, _) = try Self.exports([.heartbeatSeries(series, beats: Self.beats)], exporter) + try #require(exports.count == 1) + let context = try Self.reference(event: exports[0].event) + let reference = try HealthKitAssembly(context: context.event).convertHeartbeatSeries( + HealthKitHeartbeatSeriesRecord(series: series, heartbeats: Self.beats), + request: .init(context: context) + ) + #expect(exports[0].graph?.json == reference.primary.graph.json) + #expect(exports[0].source.sourceType == .heartbeatSeries) + } + + @Test("A workout-route record is a recording document under an authorized route policy") + func authorizedWorkoutRouteRecord() throws { + let exporter = try Fixtures.exporter { $0.route = .authorized } + let route = try StoredSampleFixtures.seriesSample( + HKWorkoutRoute.self, + sampleType: HKSeriesType.workoutRoute(), + shape: GoldenCase.seriesShape(uuid: 0xE3, duration: 1) + ) + let (exports, _) = try Self.exports([.workoutRoute(route, locations: GoldenCase.routeLocations)], exporter) + try #require(exports.count == 1) + let context = try Self.reference(event: exports[0].event) { $0.routeDisclosure = .authorized } + let reference = try #require(try HealthKitAssembly(context: context.event).convertWorkoutRoute( + HealthKitWorkoutRouteRecord(route: route, locations: GoldenCase.routeLocations), + request: .init(context: context) + )) + #expect(exports[0].graph?.json == reference.primary.graph.json) + } + + @Test("A route the policy omits delivers nothing, neither graph nor refusal, and holds its event until release") + func omittedWorkoutRouteDeliversNothing() throws { + let storage = LedgerCountingStorage() + let exporter = try Fixtures.exporter(sequencer: ExchangeEventSequencer(storage: storage)) + let route = try StoredSampleFixtures.seriesSample( + HKWorkoutRoute.self, + sampleType: HKSeriesType.workoutRoute(), + shape: GoldenCase.seriesShape(uuid: 0xE4, duration: 1) + ) + let heartRate = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0xE5)) + let (exports, receipt) = try Self.exports([.workoutRoute(route, locations: GoldenCase.routeLocations), .sample(heartRate)], exporter) + try #require(exports.map(\.source.uuid) == [heartRate.uuid], "the omitted route is not reported, and the export continues") + #expect(exports[0].warnings.isEmpty) + let key = try #require(ExchangeEventKey.active(route)) + #expect(try storage.holdsReservation(for: key)) + receipt.release() + #expect(try !storage.holdsReservation(for: key)) + } + + @Test("E1: a duplicated ECG symptom is refused as a duplicate, on every OS") + func duplicatedSymptomIsRefusedAsSuch() throws { + let exporter = try Fixtures.exporter() + let symptom = try GoldenCase.symptom(uuid: GoldenFixtures.uuid(0xE7)) + let (exports, _) = try Fixtures.collect(exporter, [try Fixtures.electrocardiogram(uuid: 0xE6, symptoms: [symptom, symptom])]) + try #require(exports.count == 1) + guard case .refused(let reason) = exports[0].outcome else { + Issue.record("expected a refusal, got \(exports[0].outcome)") + return + } + #expect(reason == .ecgEvidence(.duplicateSymptomSource(symptom.uuid))) + } +} + +#endif From a694062500aa9f2983a49b41d68e9b35716c4d8a Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 10:36:36 +0200 Subject: [PATCH 015/220] Test the Identity Scope's Ledger Fingerprint in the Contract Suite OpaqueIdentityScope.ledgerFingerprint must separate scopes by key id, epoch, key and systems, but only the HealthKit exporter's G3 pairwise test checked it. Dropping the key id from the fingerprint (review mutation M2k) passed the GroveFHIR suite, so a build or platform that runs only the contract's tests would miss the regression. - GroveFHIRTests gains LedgerFingerprintTests. Scopes that differ only in the key id, the epoch, the key, the ten opaque systems, the event system or the entry-node system fingerprint pairwise apart, and the test names any colliding pair. Equal scopes fingerprint equal, as an unpadded base64url SHA-256 digest that does not contain the key. - The HealthKit suite's ledgerFingerprintIsKeyed is removed, because the new tests cover everything it checked. G3 keeps its key-id perturbation. Verified by mutation, each run against the new suite (GroveFHIRTests): - M2k, key id dropped from the parts: fails ("key id shares its ledger fingerprint with base"). - Epoch dropped: fails ("epoch shares ..."). - systems.all replaced by systems.opaque.all: fails ("event system shares ..."). G1 verification finding: gates-mutations nit (M2k caught only by the HealthKit suite). Output unchanged: test-only change. Co-Authored-By: Claude Opus 5.5 --- .../LedgerFingerprintTests.swift | 83 +++++++++++++++++++ ...ealthKitFHIRExporterFingerprintTests.swift | 11 --- 2 files changed, 83 insertions(+), 11 deletions(-) create mode 100644 Tests/GroveFHIRTests/ExchangeLedger/LedgerFingerprintTests.swift diff --git a/Tests/GroveFHIRTests/ExchangeLedger/LedgerFingerprintTests.swift b/Tests/GroveFHIRTests/ExchangeLedger/LedgerFingerprintTests.swift new file mode 100644 index 000000000..ade62ee95 --- /dev/null +++ b/Tests/GroveFHIRTests/ExchangeLedger/LedgerFingerprintTests.swift @@ -0,0 +1,83 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(CryptoKit) +import CryptoKit +#else +import Crypto +#endif +import Foundation +@testable import GroveFHIRContract +import Testing + + +/// The identity scope's ledger fingerprint, which every exporter's context fingerprint carries so that a +/// reservation is never reused under another scope. +@Suite +struct LedgerFingerprintTests { + private static let key = SymmetricKey(data: Data(repeating: 0x42, count: 32)) + + private static func systems( + root: IdentifierSystem = "https://study.example.org/fhir", + keyID: String = "test" + ) throws -> DeploymentIdentifierSystems { + try DeploymentIdentifierSystems.derived(root: root, keyID: keyID, epoch: EventSequence(1)) + } + + private static func scope( + systems: DeploymentIdentifierSystems, + keyID: String = "test", + epoch: UInt64 = 1, + key: SymmetricKey = Self.key + ) throws -> OpaqueIdentityScope { + try OpaqueIdentityScope(systems: systems, keyID: keyID, epoch: EventSequence(epoch), key: key) + } + + @Test("Scopes that differ only in key id, epoch, key, or one group of systems fingerprint pairwise apart") + func everyScopeInputSeparatesTheFingerprint() throws { + let systems = try Self.systems() + let otherRoot = try Self.systems(root: "https://other.example.org/fhir") + let scopes = [ + ("base", try Self.scope(systems: systems)), + ("key id", try Self.scope(systems: systems, keyID: "other")), + ("epoch", try Self.scope(systems: systems, epoch: 2)), + ("key", try Self.scope(systems: systems, key: SymmetricKey(data: Data(repeating: 7, count: 32)))), + ("opaque systems", try Self.scope(systems: try DeploymentIdentifierSystems( + opaque: try Self.systems(keyID: "other").opaque, + event: systems.event, + entryNode: systems.entryNode + ))), + ("event system", try Self.scope(systems: try DeploymentIdentifierSystems( + opaque: systems.opaque, + event: otherRoot.event, + entryNode: systems.entryNode + ))), + ("entry-node system", try Self.scope(systems: try DeploymentIdentifierSystems( + opaque: systems.opaque, + event: systems.event, + entryNode: otherRoot.entryNode + ))) + ] + let fingerprints = scopes.map { name, scope in (name, scope.ledgerFingerprint) } + for (index, (name, fingerprint)) in fingerprints.enumerated() { + for (earlier, earlierFingerprint) in fingerprints[.. Date: Sun, 4 Oct 2026 10:36:36 +0200 Subject: [PATCH 016/220] Test the Producer's Refusal of Facts the Ledger Cannot Read Back The G1 verification said ExchangeProducer.ConfigurationError.unfreezableFacts was unreachable and asked for it to be removed in favour of a preconditionFailure. It is reachable. URLComponents().url, and also NSURL(string: ""), is a URL whose text is empty (checked on this macOS 27 toolchain). StudyEnrollment accepts it as its protocol canonical. The ledger then stores "" as protocolURL, and Canonical parsing cannot read that back, so PreparedFacts refuses the facts. A preconditionFailure there would crash the app at producer construction over a configuration fault. The case therefore stays, and this commit covers it: - The case's doc names that example. - ExchangeProducerTests gains unfreezableFactsAreRefused, which builds the producer with that enrollment and expects .unfreezableFacts; a well-formed enrollment still builds. - The diagnostic test now includes the case. Verified by mutation: with PreparedFacts.init using the caller's facts instead of decoding its own bytes, the new test fails ("an error was expected but none was thrown"). ExchangeProducerTests and OpaqueIdentityScopeRootTests pass on the fixed tree. G1 verification finding: deviations-concurrency minor (unfreezableFacts), rejected with the reason above. Output unchanged: no source behaviour changes, only a doc comment. Co-Authored-By: Claude Opus 5.5 --- .../GroveFHIRContract/ExchangeProducer.swift | 3 ++- .../ExchangeProducerTests.swift | 20 ++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/Sources/GroveFHIRContract/ExchangeProducer.swift b/Sources/GroveFHIRContract/ExchangeProducer.swift index 5e4f58dd7..63d5ca31b 100644 --- a/Sources/GroveFHIRContract/ExchangeProducer.swift +++ b/Sources/GroveFHIRContract/ExchangeProducer.swift @@ -23,7 +23,8 @@ public final class ExchangeProducer: Sendable { case duplicateStudy(BusinessIdentifier) /// Two enrollments carry the same enrollment identifier. case duplicateEnrollment(BusinessIdentifier) - /// The application, host or studies do not survive the ledger's encoding, so no event could freeze them. + /// The application, host or studies do not survive the ledger's encoding, so no event could freeze them, + /// such as a study whose protocol canonical has an empty URL, which no canonical text states. case unfreezableFacts /// The registered diagnostic: every configuration fault is a deployment defect. diff --git a/Tests/GroveHealthKitFHIRTests/ExchangeProducerTests.swift b/Tests/GroveHealthKitFHIRTests/ExchangeProducerTests.swift index 71b6bbe14..718219ac1 100644 --- a/Tests/GroveHealthKitFHIRTests/ExchangeProducerTests.swift +++ b/Tests/GroveHealthKitFHIRTests/ExchangeProducerTests.swift @@ -196,6 +196,23 @@ struct ExchangeProducerTests { #expect(try Self.producer(studies: [Self.enrollment(name: "a"), Self.enrollment(name: "b")]).studies.count == 2) } + @Test("Facts the ledger cannot read back are refused: a study protocol canonical with an empty URL") + func unfreezableFactsAreRefused() throws { + // Foundation builds a URL with empty text from empty components; no canonical text states it. + let empty = try #require(URLComponents().url) + #expect(empty.absoluteString.isEmpty) + let study = try StudyEnrollment( + study: Self.identifier("https://study.example.org/fhir/study", "a"), + protocolURL: FHIRPrimitive(Canonical(empty)), + protocolVersion: "1", + enrollment: Self.identifier("https://study.example.org/fhir/enrollment", "enrollment-a") + ) + #expect(throws: ExchangeProducer.ConfigurationError.unfreezableFacts) { + try Self.producer(studies: [study]) + } + #expect(try Self.producer(studies: [Self.enrollment(name: "a")]).studies.count == 1) + } + @Test("Every configuration fault reports the unclassified input diagnostic at the producer") func configurationFaultsReportOneDiagnostic() throws { let identifier = try Self.identifier("https://study.example.org/fhir/study", "s") @@ -203,7 +220,8 @@ struct ExchangeProducerTests { .reservedSubjectIdentifierSystem(identifier.system), .reservedStudyIdentifierSystem(identifier.system), .duplicateStudy(identifier), - .duplicateEnrollment(identifier) + .duplicateEnrollment(identifier), + .unfreezableFacts ] for fault in faults { #expect(fault.diagnostic.code == ExchangeGraphRule.mobileInputUnclassified.rawValue) From dfb4dac05478268cdc7246b799712300061fb414 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 10:37:03 +0200 Subject: [PATCH 017/220] Note the Reservations a Reserve Will Hold Inside Its Transaction The in-flight protection from b53930c4 scoped a reserve's keys by the storage object, or by the sequencer for a value-type storage. Sequencers over two objects or values in front of one backing store therefore did not see each other's reserves. A release could remove a reservation that another call had just reused and committed but not yet held, and that call's redelivery became a new event. MHC as specified (spec 5.3 and 5.5) creates exactly this setup, because FHIRExchangeLedger.sequencer(accountDataGeneration:) runs per batch. The verification reproduced the race with two wrapper objects, two value wrappers, and two FileStorage objects on one directory. How the protection works now: - A reserve notes the exact handles its transaction returns. It does this from inside the transaction, before the commit, and turns them into holds in one locked step after it, or drops them when the transaction did not commit. The notes live in a per-call HoldRegistry.Notes and are deduplicated under the registry lock, so an attempt the storage runs again notes nothing twice. - finish removes a reservation only when, checked inside its own transaction, no live call holds the handle and no reserve has noted it. A storage runs one process's transactions one at a time. So a reserve whose transaction ran first has already noted the handle, and one that runs after the removal no longer finds the reservation. - Handles include the producer instance, which every ledger mints for itself (C4 forbids cloning a ledger). They are therefore unique across ledgers and the same through every object, value or sequencer in front of one ledger. LedgerIdentity, the AnyClass branch, the ledger property and the per-ledger key map are removed. HoldRegistry.mayBeReused(_:in:) is renamed isHeld(_:). - The verification's option (a), scoping keys alone process-wide, is not taken. It couples unrelated ledgers in one process: a parallel HealthKit test that reserves the same fixture record on the shared registry would keep another test's reservation. The test that a reserve of the same key on another ledger keeps nothing fails under key-only scoping. - One behaviour changes at the boundary. A reserve that has not started its transaction when the release's transaction runs is now serialized after the release. It finds the reservation removed, takes a new event and holds it. Before, its keys counted as in flight from the start of the call, so it reused the released event. The old G9f in-flight test now checks the serial outcome. In both versions, a reservation a call holds is never removed. - Bodies now note handles in process memory until the call returns. Storage.transaction and the article therefore promise no effect outside the transaction "that outlasts the call", which still lets a storage run an attempt again. Tests (GroveFHIRTests, ExchangeEventHoldRaceTests): - The verification's race, with the reuse gated after its commit and before its hold, through two storage objects, two storage values (parameterized), and two FileStorage objects on one directory. Each case checks that the reservation is kept and that the reusing call's redelivery is an exact retry. - A reservation that another ledger is about to hold under the same key keeps nothing in this ledger. - A release whose transaction runs before a waiting reserve's removes the reservation, and that reserve's redelivery retries its own new event. - G7 checks that a failed attempt leaves none of the handles it would have returned noted. Verified by mutation (GroveFHIRTests ledger suites): - b17f10d0 mechanism restored: the objects, values and file cases fail, and so does the waiting-reserve case. - Notes taken after the commit: the objects, values and file cases fail. - finish checking holds only: the objects, values and file cases fail. - Notes never ended: G7, G8, G9a, G9d and the G9f removal cases fail. - Key-only scoping, option (a): the other-ledger case fails. G1 verification finding: deviations-concurrency minor (sequencers over separate storage wrappers). The MHC spec needs no change, because FHIRExchangeLedger may build a sequencer and a storage object per batch. Audit ledger: section 2 finding 3 (release ownership). Output unchanged, verified by the GroveHealthKitFHIR macOS suite (goldens and the G17 digest table) and the GroveFHIR suite. Co-Authored-By: Claude Opus 5.5 --- .../ExchangeEventSequencer+Holds.swift | 63 ++++--- .../ExchangeEventSequencer.swift | 43 ++--- .../ExchangeLedgerStorage.md | 4 +- .../ExchangeEventHoldRaceTests.swift | 162 +++++++++++++++--- .../ExchangeEventHoldTests.swift | 4 +- .../ExchangeLedgerEntryTests.swift | 10 +- .../ExchangeLedger/LedgerFixtures.swift | 6 +- 7 files changed, 198 insertions(+), 94 deletions(-) diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer+Holds.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer+Holds.swift index 4b48812f2..3d47a64d2 100644 --- a/Sources/GroveFHIRContract/ExchangeEventSequencer+Holds.swift +++ b/Sources/GroveFHIRContract/ExchangeEventSequencer+Holds.swift @@ -9,65 +9,62 @@ import Foundation -/// Which reservations the live calls of this process still hold, whether any holder released one, and which keys -/// of which ledger a reserve is in flight for. +/// Which reservations the live calls of this process hold or are about to hold, and whether any holder released one. /// /// The ledger's entries hold no per-call state: a reservation is removed when the last live holder in this /// process finishes and any holder released it, so overlapping exports of one record never remove each -/// other's reservation, and a call that throws leaves its reservations for the redelivery. A reserve registers -/// its keys before its transaction and turns them into holds in one step after it, so a reservation it may reuse -/// is never seen unused in between. Handles include the producer instance, which every ledger mints for itself, -/// so holds need no ledger; keys in flight are scoped to their ledger. One registry serves every storage. Holds -/// do not span processes; the lock is never held across I/O. +/// other's reservation, and a call that throws leaves its reservations for the redelivery. A reserve notes the +/// reservations its transaction returns from inside that transaction and turns them into holds in one step after +/// it, so a reservation it is about to hold is never seen unused in between. Handles include the producer +/// instance, which every ledger mints for itself, so they are unique across ledgers and the same through every +/// storage object or sequencer in front of one ledger; one registry serves every storage. Holds do not span +/// processes; the lock is never held across I/O. final class HoldRegistry: @unchecked Sendable { // `holds` and `reserving` are guarded by `lock`. + /// The reservations one reserve call noted, so an attempt the storage runs again notes nothing twice. + final class Notes: @unchecked Sendable { // `handles` is guarded by the registry's `lock`. + fileprivate var handles: Set = [] + } + private struct Hold { var live: Int var released: Bool } - /// One event key of one ledger. - private struct LedgerEventKey: Hashable { - let ledger: ObjectIdentifier - let key: ExchangeEventKey - } - /// The registry every sequencer of this process shares. static let shared = HoldRegistry() private let lock = NSLock() private var holds: [ExchangeEventReservation.Handle: Hold] = [:] - private var reserving: [LedgerEventKey: Int] = [:] + /// The reservations reserving transactions returned whose calls have not yet taken their holds. + private var reserving: [ExchangeEventReservation.Handle: Int] = [:] - /// Marks a reserve of `keys` in `ledger` as in flight; called before its transaction. - func beginReserving(_ keys: some Sequence, in ledger: ObjectIdentifier) { + /// Notes that the reserve call `notes` belongs to is about to hold `handles`; called inside its transaction, + /// before the commit, by every attempt. + func beginReserving(_ handles: some Sequence, in notes: Notes) { lock.lock() defer { lock.unlock() } - for key in keys { - reserving[LedgerEventKey(ledger: ledger, key: key), default: 0] += 1 + for handle in handles where notes.handles.insert(handle).inserted { + reserving[handle, default: 0] += 1 } } - /// Ends a reserve begun for `keys` in `ledger` and takes one hold per handle it returned, in one step; `handles` - /// is empty when the reserving transaction did not commit. - func endReserving( - _ keys: some Sequence, - in ledger: ObjectIdentifier, - acquiring handles: some Sequence - ) { + /// Ends the notes of one reserve call and takes one hold per handle in `acquired`, in one step; `acquired` is + /// empty when the reserving transaction did not commit. + func endReserving(_ notes: Notes, acquiring acquired: some Sequence) { lock.lock() defer { lock.unlock() } - for handle in handles { + for handle in acquired { holds[handle, default: Hold(live: 0, released: false)].live += 1 } - for key in keys { - let scoped = LedgerEventKey(ledger: ledger, key: key) - let remaining = (reserving[scoped] ?? 1) - 1 - reserving[scoped] = remaining > 0 ? remaining : nil + for handle in notes.handles { + let remaining = (reserving[handle] ?? 1) - 1 + reserving[handle] = remaining > 0 ? remaining : nil } + notes.handles = [] } /// Ends one hold per handle and returns the handles whose last live holder just finished and that some @@ -94,12 +91,12 @@ final class HoldRegistry: @unchecked Sendable { // `holds` and `reserving` are g return removable } - /// Whether a live call holds `handle`, or a reserve of its key in `ledger` is in flight and may reuse it. - func mayBeReused(_ handle: ExchangeEventReservation.Handle, in ledger: ObjectIdentifier) -> Bool { + /// Whether a live call holds `handle`, or a reserving transaction returned it and its call is about to hold it. + func isHeld(_ handle: ExchangeEventReservation.Handle) -> Bool { lock.lock() defer { lock.unlock() } - return holds[handle] != nil || reserving[LedgerEventKey(ledger: ledger, key: handle.key)] != nil + return holds[handle] != nil || reserving[handle] != nil } } diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift index a24520334..72e71d4d8 100644 --- a/Sources/GroveFHIRContract/ExchangeEventSequencer.swift +++ b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift @@ -9,10 +9,6 @@ public import Foundation -/// The identity of a ledger whose storage is not a class instance. -private final class LedgerIdentity: Sendable {} - - /// The exchange-event ledger of one installation: it hands out event sequences and keeps what each /// event is rebuilt from until the caller releases it. /// @@ -36,8 +32,8 @@ public final class ExchangeEventSequencer: Sendable { /// Runs `body` as one transaction and returns its result. /// /// The transaction is valid only inside `body`. Grove never calls `transaction` from inside `body`, - /// and its bodies have no effect outside the transaction, so a storage may discard an attempt and - /// run `body` again. A `body` that throws commits nothing. + /// and its bodies have no effect outside the transaction that outlasts the call, so a storage may + /// discard an attempt and run `body` again. A `body` that throws commits nothing. func transaction(_ body: (any Transaction) throws -> R) throws -> R } @@ -69,13 +65,8 @@ public final class ExchangeEventSequencer: Sendable { } let storage: any Storage - /// Which reservations live calls in this process still hold, and which keys a reserve is in flight for. + /// Which reservations live calls in this process hold or are about to hold. let holds: HoldRegistry - /// The ledger in ``holds``: the storage object, so sequencers over one storage share their reserves in flight. - /// A storage that is not a class instance is identified by this sequencer alone. - let ledger: ObjectIdentifier - /// Keeps the identity of a value-type storage's ledger alive as long as this sequencer. - private let identity: LedgerIdentity /// Creates a sequencer over the application's storage. /// @@ -85,11 +76,8 @@ public final class ExchangeEventSequencer: Sendable { } init(storage: any Storage, holds: HoldRegistry) { - let identity = LedgerIdentity() self.storage = storage self.holds = holds - self.identity = identity - self.ledger = type(of: storage) is AnyClass ? ObjectIdentifier(storage as AnyObject) : ObjectIdentifier(identity) } /// A sequencer over a fresh ``InMemoryStorage``, for tests, previews and single-process tools. @@ -169,17 +157,18 @@ extension ExchangeEventSequencer { throw ExchangeIdentityError.invalidInstant } let ordered = Set(requests).sorted { ($0.key.rawValue, $0.fingerprint) < ($1.key.rawValue, $1.fingerprint) } - let keys = Set(ordered.map(\.key)) - // In flight from before the transaction until its holds are taken, so no release removes a reservation - // this call may be reusing in between. - holds.beginReserving(keys, in: ledger) + // Noted inside the transaction, before it commits, until the holds are taken, so no release removes a + // reservation this call is about to hold in between. + let notes = HoldRegistry.Notes() var acquired: [ExchangeEventReservation.Handle] = [] defer { - holds.endReserving(keys, in: ledger, acquiring: acquired) + holds.endReserving(notes, acquiring: acquired) } let reserved = try storage.transaction { transaction in var reserving = ReserveCall(transaction: transaction, current: current, instantMilliseconds: instantMilliseconds) - return try reserving.reserve(ordered) + let reserved = try reserving.reserve(ordered) + holds.beginReserving(reserved.values.map(\.handle), in: notes) + return reserved } acquired = reserved.values.map(\.handle) return reserved @@ -190,9 +179,8 @@ extension ExchangeEventSequencer { /// `released` says the caller's output is durably handed off. When the last live holder of a /// reservation in this process finishes and any holder released it, the reservation is removed, but /// only while the key still holds exactly that reservation and, checked inside the removing transaction, - /// no live call holds it and no reserve of its key is in flight on this storage. `keys` are forgotten - /// whatever they hold, and only when `released` is true. Opens one transaction when anything is to be - /// removed, none otherwise. + /// no call in this process holds it or is about to. `keys` are forgotten whatever they hold, and only + /// when `released` is true. Opens one transaction when anything is to be removed, none otherwise. package func finish( _ held: [ExchangeEventReservation.Handle], released: Bool, @@ -204,9 +192,10 @@ extension ExchangeEventSequencer { return } try storage.transaction { transaction in - // A reserve that registered before this check may reuse the reservation, so it stays; one that registers - // later starts its transaction after this one, as a storage runs a process's transactions one at a time. - for handle in removable where !holds.mayBeReused(handle, in: ledger) { + // A reserve whose transaction returned the reservation noted it there, so it stays; a reserve whose + // transaction runs after this one no longer finds it, as a storage runs a process's transactions one at + // a time. + for handle in removable where !holds.isHeld(handle) { let key = LedgerKey.event(handle.key) guard let value = try transaction.read(key) else { continue diff --git a/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md b/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md index c2e8c49de..9979937ab 100644 --- a/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md +++ b/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md @@ -45,7 +45,7 @@ What Grove promises a storage in return: - Keys are ASCII from `[A-Za-z0-9_/-]` and at most 64 bytes: `producer`, `event/` and `facts/`. - Values are UTF-8 JSON, typically under 1 KiB; accept values up to 1 MiB, as facts grow with the number of studies. -- Grove never nests transactions, never lets a transaction escape its body, and its bodies have no effect outside the transaction, so a storage may discard an attempt and run the body again. +- Grove never nests transactions, never lets a transaction escape its body, and its bodies have no effect outside the transaction that outlasts the call, so a storage may discard an attempt and run the body again. - `keys(prefixedBy:)` is called only by ``ExchangeEventSequencer/reset()`` and ``ExchangeEventSequencer/forgetReservations(madeBefore:)``. - One storage holds one ledger and nothing else. @@ -76,7 +76,7 @@ Both the cutoff and the stored instants are on the caller's clock, so choose one The entries hold no per-call state. Live calls are tracked in process memory: when the last call in the process that holds an event finishes and any of them released it, the event's reservation is removed, and otherwise it stays for the redelivery. -A reserve registers its keys before its transaction, and the removing transaction checks them, so a release never removes a reservation that a call on the same storage object in the same process is about to reuse; this relies on the storage running one process's transactions one at a time, as every backend above does. +A reserve notes the reservations its transaction returns from inside that transaction until it holds them, and the removing transaction checks those notes and the holds, so a release never removes a reservation another call in the process holds or is about to hold, whichever storage object, value or sequencer either call goes through; this relies on the storage running one process's transactions one at a time, as every backend above does. A release only ever removes the exact reservation its call made, never a successor's or one from before a reset. The one exception is a retraction's receipt: on release it forgets each deleted record's active reservation, whatever that reservation is, because no export will release it once the record is gone. Holds do not span processes; when two live processes share one storage, a release in one can remove a reservation the other still holds, and the other's redelivery then becomes a new event, a duplicate and never a reuse. diff --git a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldRaceTests.swift b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldRaceTests.swift index 66313faf2..f0a149fd3 100644 --- a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldRaceTests.swift +++ b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldRaceTests.swift @@ -12,34 +12,78 @@ import Foundation import Testing -/// Blocks the next transaction until signalled, so a test can run another call before it. -private final class GateStorage: ExchangeEventSequencer.Storage, @unchecked Sendable { // `gateNext` is guarded by `lock`. - let base = ExchangeEventSequencer.InMemoryStorage() - /// Signalled when the gated transaction is reached. +/// Forwards to a storage and blocks the next transaction until signalled, before it starts or after it committed, +/// so a test can run another call in between. +private final class GateStorage: ExchangeEventSequencer.Storage, @unchecked Sendable { // `gate` is guarded by `lock`. + enum Point { + /// Before the transaction starts. + case before + /// After the transaction committed, before it returns to the sequencer. + case afterCommit + } + + let base: any ExchangeEventSequencer.Storage + /// Signalled when the gated transaction reaches its point. let entered = DispatchSemaphore(value: 0) - /// Lets the gated transaction run. + /// Lets the gated transaction continue. let proceed = DispatchSemaphore(value: 0) private let lock = NSLock() - private var gateNext = false + private var gateNext: Point? + + init(base: any ExchangeEventSequencer.Storage = ExchangeEventSequencer.InMemoryStorage()) { + self.base = base + } - func gate() { + func gate(_ point: Point = .before) { lock.lock() defer { lock.unlock() } - gateNext = true + gateNext = point } func transaction(_ body: (any ExchangeEventSequencer.Transaction) throws -> R) throws -> R { lock.lock() let gated = gateNext - gateNext = false + gateNext = nil lock.unlock() - if gated { - entered.signal() - proceed.wait() + if gated == .before { + wait() + } + let result = try base.transaction(body) + if gated == .afterCommit { + wait() } - return try base.transaction(body) + return result + } + + private func wait() { + entered.signal() + proceed.wait() + } +} + + +/// Another object in front of one storage, as an application may build per call. +private final class StorageWrapper: ExchangeEventSequencer.Storage { + let base: any ExchangeEventSequencer.Storage + + init(_ base: any ExchangeEventSequencer.Storage) { + self.base = base + } + + func transaction(_ body: (any ExchangeEventSequencer.Transaction) throws -> R) throws -> R { + try base.transaction(body) + } +} + + +/// A value in front of one storage, which has no object identity at all. +private struct StorageValue: ExchangeEventSequencer.Storage { + let base: any ExchangeEventSequencer.Storage + + func transaction(_ body: (any ExchangeEventSequencer.Transaction) throws -> R) throws -> R { + try base.transaction(body) } } @@ -50,7 +94,17 @@ private final class ReservedBox: @unchecked Sendable { } -/// A release racing a reserve of the same key never removes a reservation the reserve reuses. +/// A release racing a reuse of the same reservation: what was reserved first, reused, kept and redelivered. +private struct ReuseOutcome { + let first: ExchangeEventReservation? + let reused: ExchangeEventReservation? + let kept: Bool + let redelivery: ExchangeEventReservation? +} + + +/// A release racing a reserve of the same key never removes a reservation the reserve is about to hold, through +/// whichever object or value in front of the storage either call goes. @Suite struct ExchangeEventHoldRaceTests { private typealias Fixtures = LedgerFixtures @@ -80,11 +134,11 @@ struct ExchangeEventHoldRaceTests { #expect(redelivery == first, "its redelivery is an exact retry") try sequencer.finish(second.values.map(\.handle) + redelivery.values.map(\.handle), released: true, forgetting: []) #expect(try Fixtures.stored(LedgerKey.event(request.key), in: storage.base) == nil) - #expect(!Fixtures.mayBeReused(first[request]?.handle, by: sequencer)) + #expect(!Fixtures.isHeld(first[request]?.handle, by: sequencer)) } - @Test("G9f: a release while a reserve of the key is in flight keeps the reservation for that reserve") - func releaseWhileAReserveIsInFlight() throws { + @Test("G9f: a release whose transaction runs before a waiting reserve's removes the reservation; that reserve holds a new one") + func releaseBeforeAWaitingReserve() throws { let storage = GateStorage() let sequencer = Fixtures.sequencer(storage) let request = Fixtures.request("race") @@ -97,28 +151,88 @@ struct ExchangeEventHoldRaceTests { box.reserved = (try? sequencer.reserve([request], at: Fixtures.instant, facts: facts)) ?? [:] reserved.signal() }.start() - // The second call registered its reserve and waits to open its transaction; the last holder releases now. + // The second call waits to open its transaction, so it has seen nothing yet; the last holder releases now. storage.entered.wait() try sequencer.finish(first.values.map(\.handle), released: true, forgetting: []) - #expect(try Fixtures.stored(LedgerKey.event(request.key), in: storage.base) != nil) + #expect(try Fixtures.stored(LedgerKey.event(request.key), in: storage.base) == nil) storage.proceed.signal() reserved.wait() - #expect(box.reserved == first, "the second call reused the reservation") + let second = try #require(box.reserved[request]) + #expect(second.handle != first[request]?.handle, "the second call's transaction ran after the removal") + let redelivery = try sequencer.reserve([request], at: Fixtures.instant, facts: facts) + #expect(redelivery == box.reserved, "the second call's redelivery is an exact retry of its own event") + } + + /// The last holder releases through `holder` while a reserve through `reuser` has committed its reuse of the same + /// reservation but not yet taken its hold; then the reusing call redelivers before it releases. + private func releaseDuringAReuse( + holder: any ExchangeEventSequencer.Storage, + reuser: any ExchangeEventSequencer.Storage, + gate: GateStorage, + backing: any ExchangeEventSequencer.Storage + ) throws -> ReuseOutcome { + let registry = HoldRegistry() + let holding = ExchangeEventSequencer(storage: holder, holds: registry) + let reusing = ExchangeEventSequencer(storage: reuser, holds: registry) + let request = Fixtures.request("wrapped") + let facts = try Fixtures.facts() + let first = try holding.reserve([request], at: Fixtures.instant, facts: facts) + let box = ReservedBox() + let reserved = DispatchSemaphore(value: 0) + gate.gate(.afterCommit) + Thread { + box.reserved = (try? reusing.reserve([request], at: Fixtures.instant, facts: facts)) ?? [:] + reserved.signal() + }.start() + // The reuse committed and returns to its sequencer, which has not taken its hold yet. + gate.entered.wait() + try holding.finish(first.values.map(\.handle), released: true, forgetting: []) + let kept = try Fixtures.stored(LedgerKey.event(request.key), in: backing) != nil + gate.proceed.signal() + reserved.wait() + let redelivery = try reusing.reserve([request], at: Fixtures.instant, facts: facts) + return ReuseOutcome(first: first[request], reused: box.reserved[request], kept: kept, redelivery: redelivery[request]) + } + + @Test("G9f: a release keeps a reservation a call is about to hold through another object or value over one storage", arguments: [false, true]) + func releaseKeepsAReuseThroughAnotherFront(throughValues: Bool) throws { + let backing = ExchangeEventSequencer.InMemoryStorage() + let gate = GateStorage(base: backing) + let holder: any ExchangeEventSequencer.Storage = throughValues ? StorageValue(base: backing) : StorageWrapper(backing) + let reuser: any ExchangeEventSequencer.Storage = throughValues ? StorageValue(base: gate) : gate + let outcome = try releaseDuringAReuse(holder: holder, reuser: reuser, gate: gate, backing: backing) + #expect(outcome.reused != nil && outcome.reused == outcome.first, "the second call reused the reservation") + #expect(outcome.kept, "the release removed a reservation the second call is about to hold") + #expect(outcome.redelivery == outcome.reused, "the second call's redelivery is an exact retry") + } + + @Test("G9f: a release keeps a reservation a call is about to hold through another file storage on the same directory") + func releaseKeepsAReuseThroughAnotherFileStorage() throws { + let directory = FileManager.default.temporaryDirectory.appendingPathComponent("ledger-\(UUID().uuidString)", isDirectory: true) + defer { + try? FileManager.default.removeItem(at: directory) + } + let holder = try FileStorage(directory: directory) + let gate = GateStorage(base: try FileStorage(directory: directory)) + let outcome = try releaseDuringAReuse(holder: holder, reuser: gate, gate: gate, backing: holder) + #expect(outcome.reused != nil && outcome.reused == outcome.first, "the second call reused the reservation") + #expect(outcome.kept, "the release removed a reservation the second call is about to hold") + #expect(outcome.redelivery == outcome.reused, "the second call's redelivery is an exact retry") } - @Test("G9f: a reserve in flight on another storage does not keep this ledger's reservation") - func reserveInFlightElsewhereKeepsNothing() throws { + @Test("G9f: a reservation another ledger is about to hold under the same key does not keep this ledger's") + func reserveOfTheKeyElsewhereKeepsNothing() throws { let registry = HoldRegistry() let other = GateStorage() let request = Fixtures.request("race") let facts = try Fixtures.facts() let reserved = DispatchSemaphore(value: 0) - other.gate() + other.gate(.afterCommit) Thread { _ = try? ExchangeEventSequencer(storage: other, holds: registry).reserve([request], at: Fixtures.instant, facts: facts) reserved.signal() }.start() - // The same key is in flight on another ledger while this one releases it. + // Another ledger committed a reservation of the same key and is about to hold it while this one releases. other.entered.wait() let storage = ExchangeEventSequencer.InMemoryStorage() let sequencer = ExchangeEventSequencer(storage: storage, holds: registry) diff --git a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldTests.swift b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldTests.swift index 31918cc0a..5bdb3ae14 100644 --- a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldTests.swift +++ b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldTests.swift @@ -32,7 +32,7 @@ struct ExchangeEventHoldTests { #expect(again == first) try sequencer.finish(again.values.map(\.handle), released: true, forgetting: []) #expect(try !Self.isReserved(request, in: storage)) - #expect(!Fixtures.mayBeReused(again[request]?.handle, by: sequencer)) + #expect(!Fixtures.isHeld(again[request]?.handle, by: sequencer)) } @Test("G8: after a crash between reserve and release, the next process reuses and removes the reservation") @@ -74,7 +74,7 @@ struct ExchangeEventHoldTests { try sequencer.finish(winner.values.map(\.handle), released: true, forgetting: []) try sequencer.finish(loser.values.map(\.handle), released: false, forgetting: []) #expect(try !Self.isReserved(request, in: storage)) - #expect(!Fixtures.mayBeReused(winner[request]?.handle, by: sequencer)) + #expect(!Fixtures.isHeld(winner[request]?.handle, by: sequencer)) } @Test("G10: a handle from before a reset releases nothing, and a replaced reservation is not removed") diff --git a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerEntryTests.swift b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerEntryTests.swift index eddbb7780..f7fd9ef54 100644 --- a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerEntryTests.swift +++ b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerEntryTests.swift @@ -247,9 +247,13 @@ struct ExchangeLedgerEntryTests { } storage.failAtCommit(false) #expect(try Fixtures.keys("", in: storage.base) == before) - #expect(Fixtures.mayBeReused(first.values.first?.handle, by: sequencer), "the first call still holds its reservation") - let unheld = requests.map { ExchangeEventReservation.Handle(key: $0.key, instance: UUID(), sequence: 1) } - #expect(!unheld.contains { Fixtures.mayBeReused($0, by: sequencer) }, "a failed reserve leaves no key in flight") + #expect(Fixtures.isHeld(first.values.first?.handle, by: sequencer), "the first call still holds its reservation") + // The reservations the failed attempts would have returned: the same instance, sequences 2 to 4. + let instance = try #require(first.values.first?.producerInstance) + let unheld = requests.flatMap { request in + (2...4).map { ExchangeEventReservation.Handle(key: request.key, instance: instance, sequence: $0) } + } + #expect(!unheld.contains { Fixtures.isHeld($0, by: sequencer) }, "a failed reserve leaves nothing noted") let retried = try sequencer.reserve(requests, at: Fixtures.instant, facts: Fixtures.facts(build: "200")) #expect(Set(retried.values.map(\.sequence.rawValue)) == ["2", "3", "4"]) } diff --git a/Tests/GroveFHIRTests/ExchangeLedger/LedgerFixtures.swift b/Tests/GroveFHIRTests/ExchangeLedger/LedgerFixtures.swift index a67397e9a..32ae7d251 100644 --- a/Tests/GroveFHIRTests/ExchangeLedger/LedgerFixtures.swift +++ b/Tests/GroveFHIRTests/ExchangeLedger/LedgerFixtures.swift @@ -63,9 +63,9 @@ enum LedgerFixtures { ExchangeEventSequencer(storage: storage, holds: HoldRegistry()) } - /// Whether a live call on `sequencer` holds `handle`, or a reserve of its key is in flight on its storage. - static func mayBeReused(_ handle: ExchangeEventReservation.Handle?, by sequencer: ExchangeEventSequencer) -> Bool { - handle.map { sequencer.holds.mayBeReused($0, in: sequencer.ledger) } ?? false + /// Whether a call through `sequencer`'s registry holds `handle` or is about to. + static func isHeld(_ handle: ExchangeEventReservation.Handle?, by sequencer: ExchangeEventSequencer) -> Bool { + handle.map { sequencer.holds.isHeld($0) } ?? false } /// The raw value stored under `key`. From 35f68942fc69e2e9ae088dda0d5963bcb302dcf8 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 10:37:04 +0200 Subject: [PATCH 018/220] State the One-at-a-Time Premise in the Ledger's Storage Contract The article said the in-flight rule relies on the storage running one process's transactions one at a time, "as every backend above does". Its own SQL row, however, allowed bare serializable isolation. Serializable engines that let transactions overlap, such as snapshot isolation with validation or optimistic concurrency, do not run them one at a time. On such an engine a release can check for holders before a concurrent reuse commits, and then remove the reservation anyway, because the reuse writes nothing the release read. The verification reproduced this with an optimistic backend that meets C1 to C5. The fix is documentation, one of the two options the verification offered. Making the reuse write instead would add a write to every reuse-only call (spec 1.5.1 cost). - SQL row, C3: a transaction that takes the write lock when it begins, such as SQLite's BEGIN IMMEDIATE. Serializable isolation whose transactions overlap also meets C3, with the cost the Holds and receipts section describes. MHC's GRDB DatabaseQueue with .immediate is the first form. - Holds and receipts: the premise is now its own sentence and names how every backend meets it (its lock, or a write-locking transaction). A storage whose serializable transactions overlap still never reuses a sequence. A release there can remove a reservation that a concurrent call has just reused, and that call's redelivery becomes a duplicate. - The Storage protocol doc says the same, so the API reference states it where an implementer reads. Tests (GroveFHIRTests): - OptimisticStorage, a test storage whose serializable transactions overlap: snapshot reads, buffered writes, backward validation, and a re-run on conflict. - G6 (concurrent reserves, releases and resets, checked by the reuse oracle) now also runs over OptimisticStorage and finds no reuse. This supports "still never reuses a sequence". - A new G9f case pins the documented outcome. The release is gated between its body and its commit, a reuse commits in between, and the holder's redelivery takes a new, higher sequence under the same instance. The change itself is documentation, so no test can fail without it; the new tests check the claims the documentation makes. G6 and the new case also pass on b17f10d0's mechanism, because the outcome does not depend on it. G1 verification finding: deviations-concurrency minor (a serializable backend whose transactions overlap). Deviation from spec 1.3: the SQL C3 cell is reworded as above. Output unchanged: documentation and tests only. Co-Authored-By: Claude Opus 5.5 --- .../ExchangeEventSequencer.swift | 5 +- .../ExchangeLedgerStorage.md | 6 +- .../ExchangeEventHoldRaceTests.swift | 26 ++++ .../ExchangeLedgerPropertyTests.swift | 18 ++- .../ExchangeLedger/OptimisticStorage.swift | 115 ++++++++++++++++++ 5 files changed, 164 insertions(+), 6 deletions(-) create mode 100644 Tests/GroveFHIRTests/ExchangeLedger/OptimisticStorage.swift diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift index 72e71d4d8..67a5941c3 100644 --- a/Sources/GroveFHIRContract/ExchangeEventSequencer.swift +++ b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift @@ -27,7 +27,10 @@ public final class ExchangeEventSequencer: Sendable { /// /// The entries belong to Grove: a storage keeps keys and values byte-exact and never interprets them. /// A conformance meets the five clauses of : atomicity, durability, - /// serializable isolation, no regression or duplication, and byte-exactness. + /// serializable isolation, no regression or duplication, and byte-exactness. Running one process's + /// transactions one at a time, as a lock or a transaction that takes the write lock when it begins does, + /// also keeps a release from removing a reservation another call has just reused; a storage whose + /// transactions overlap loses only that, and the call's redelivery becomes a duplicate, never a reuse. public protocol Storage: Sendable { /// Runs `body` as one transaction and returns its result. /// diff --git a/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md b/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md index 9979937ab..2a16630e1 100644 --- a/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md +++ b/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md @@ -57,7 +57,7 @@ What Grove promises a storage in return: | One file, rewritten atomically | Mutate a copy, write a temporary file in the same directory, rename it over the original. | `F_FULLFSYNC` on the temporary file before the rename, then `fsync` the directory. | A process lock plus `flock` on a sibling lock file that is never replaced. | Exclude the directory from backup; never sync it. | A binary property list `[String: Data]`. | | Keychain (small or pruned ledgers) | The whole map is one item, replaced in one call. | The keychain commits the item before the call returns; that the commit survives power loss is Apple's guarantee, not verified here. | A process lock, plus a lock file for app extensions sharing the item. | A this-device-only, non-synchronizable item, guarded by a token also kept in a non-backed-up file; a missing or differing token presents an empty map. | A binary property list `[String: Data]`. | | Core Data | A private context per transaction and one save, discarded on a throw. | Fully synchronous commits with a device-cache flush. | One process lock; an error merge policy fails a conflicting save, and the body runs again. | Exclude the store from backup; no CloudKit mirroring. | A string key with a uniqueness constraint and a binary value. | -| SQL database | One transaction per call over a relation with a unique key and a binary value. | The engine's fully durable commit, including the device-cache flush. | Serializable isolation, or a transaction that takes the write lock first. | Exclude the database from backup; never restore it from replicas or snapshots. | A key column with binary collation and a binary value column. | +| SQL database | One transaction per call over a relation with a unique key and a binary value. | The engine's fully durable commit, including the device-cache flush. | A transaction that takes the write lock when it begins, such as SQLite's `BEGIN IMMEDIATE`. Serializable isolation whose transactions overlap meets C3 too, with the cost described under Holds and receipts. | Exclude the database from backup; never restore it from replicas or snapshots. | A key column with binary collation and a binary value column. | ## Cost and retention @@ -76,7 +76,9 @@ Both the cutoff and the stored instants are on the caller's clock, so choose one The entries hold no per-call state. Live calls are tracked in process memory: when the last call in the process that holds an event finishes and any of them released it, the event's reservation is removed, and otherwise it stays for the redelivery. -A reserve notes the reservations its transaction returns from inside that transaction until it holds them, and the removing transaction checks those notes and the holds, so a release never removes a reservation another call in the process holds or is about to hold, whichever storage object, value or sequencer either call goes through; this relies on the storage running one process's transactions one at a time, as every backend above does. +A reserve notes the reservations its transaction returns from inside that transaction until it holds them, and the removing transaction checks those notes and the holds, so a release never removes a reservation another call in the process holds or is about to hold, whichever storage object, value or sequencer either call goes through. +This relies on the storage running one process's transactions one at a time, as every backend above does with its lock or a transaction that takes the write lock when it begins. +A storage whose serializable transactions overlap, such as one that validates optimistically, still never reuses a sequence, but there a release can remove a reservation that a concurrent call has just reused, and that call's redelivery then becomes a new event, a duplicate and never a reuse. A release only ever removes the exact reservation its call made, never a successor's or one from before a reset. The one exception is a retraction's receipt: on release it forgets each deleted record's active reservation, whatever that reservation is, because no export will release it once the record is gone. Holds do not span processes; when two live processes share one storage, a release in one can remove a reservation the other still holds, and the other's redelivery then becomes a new event, a duplicate and never a reuse. diff --git a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldRaceTests.swift b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldRaceTests.swift index f0a149fd3..038050b88 100644 --- a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldRaceTests.swift +++ b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldRaceTests.swift @@ -242,4 +242,30 @@ struct ExchangeEventHoldRaceTests { other.proceed.signal() reserved.wait() } + + @Test("G9f: over a storage whose transactions overlap, a release can remove a reservation a call just reused; a duplicate, never a reuse") + func overlappingTransactionsDuplicateNeverReuse() throws { + let storage = OptimisticStorage() + let sequencer = Fixtures.sequencer(storage) + let request = Fixtures.request("overlap") + let facts = try Fixtures.facts() + let first = try sequencer.reserve([request], at: Fixtures.instant, facts: facts) + let finished = DispatchSemaphore(value: 0) + storage.gate() + Thread { + try? sequencer.finish(first.values.map(\.handle), released: true, forgetting: []) + finished.signal() + }.start() + // The release found no holder and staged its removal; a reuse commits before the release validates. + storage.entered.wait() + let second = try sequencer.reserve([request], at: Fixtures.instant, facts: facts) + storage.proceed.signal() + finished.wait() + let held = try #require(second[request]) + #expect(second == first, "the reuse committed first") + // As the storage article states: the holder's redelivery takes a new sequence, never one handed out before. + let redelivery = try #require(try sequencer.reserve([request], at: Fixtures.instant, facts: facts)[request]) + #expect(redelivery.handle.instance == held.handle.instance) + #expect(redelivery.handle.sequence > held.handle.sequence) + } } diff --git a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerPropertyTests.swift b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerPropertyTests.swift index c34064808..858046ec3 100644 --- a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerPropertyTests.swift +++ b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeLedgerPropertyTests.swift @@ -71,6 +71,14 @@ private final class ReuseOracle: @unchecked Sendable { // `events` and `reuses` struct ExchangeLedgerPropertyTests { private typealias Fixtures = LedgerFixtures + /// A storage G6 runs over: one that runs transactions one at a time, in memory or in a file, or one whose + /// serializable transactions overlap. + enum Backend: CaseIterable, Sendable { + case memory + case file + case optimistic + } + /// One random step of the interleaving. private static func step( _ random: inout SeededGenerator, @@ -122,13 +130,17 @@ struct ExchangeLedgerPropertyTests { #expect(oracle.reuses.isEmpty, "reused: \(oracle.reuses.prefix(5))") } - @Test("G6: concurrent reservations and releases with a resetting thread never collide", arguments: [false, true]) - func concurrentCallsNeverCollide(overFile: Bool) async throws { + @Test("G6: concurrent reservations and releases with a resetting thread never collide", arguments: Backend.allCases) + func concurrentCallsNeverCollide(backend: Backend) async throws { let directory = FileManager.default.temporaryDirectory.appendingPathComponent("ledger-\(UUID().uuidString)", isDirectory: true) defer { try? FileManager.default.removeItem(at: directory) } - let storage: any ExchangeEventSequencer.Storage = overFile ? try FileStorage(directory: directory) : ExchangeEventSequencer.InMemoryStorage() + let storage: any ExchangeEventSequencer.Storage = switch backend { + case .memory: ExchangeEventSequencer.InMemoryStorage() + case .file: try FileStorage(directory: directory) + case .optimistic: OptimisticStorage() + } let sequencer = Fixtures.sequencer(storage) let oracle = ReuseOracle() let threads = 8 diff --git a/Tests/GroveFHIRTests/ExchangeLedger/OptimisticStorage.swift b/Tests/GroveFHIRTests/ExchangeLedger/OptimisticStorage.swift new file mode 100644 index 000000000..7909eb7bd --- /dev/null +++ b/Tests/GroveFHIRTests/ExchangeLedger/OptimisticStorage.swift @@ -0,0 +1,115 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +import Dispatch +import Foundation +import GroveFHIRContract + + +/// A serializable storage whose transactions overlap, as an SQL engine's serializable isolation lets them: each +/// attempt reads a snapshot and buffers its writes, and commits only if no transaction that committed after its +/// snapshot wrote a key it read or listed; otherwise it runs `body` again. It meets C1 to C5 in one process. +final class OptimisticStorage: ExchangeEventSequencer.Storage, @unchecked Sendable { // State is guarded by `lock`. + private final class Attempt: ExchangeEventSequencer.Transaction { + let snapshot: [String: Data] + var writes: [String: Data?] = [:] + var reads: Set = [] + var prefixes: [String] = [] + + init(snapshot: [String: Data]) { + self.snapshot = snapshot + } + + func read(_ key: String) throws -> Data? { + reads.insert(key) + if let write = writes[key] { + return write + } + return snapshot[key] + } + + func write(_ value: Data, for key: String) throws { + writes[key] = .some(value) + } + + func remove(_ key: String) throws { + writes[key] = .some(nil) + } + + func keys(prefixedBy prefix: String) throws -> [String] { + prefixes.append(prefix) + var keys = Set(snapshot.keys.filter { $0.hasPrefix(prefix) }) + for (key, value) in writes where key.hasPrefix(prefix) { + if value == nil { + keys.remove(key) + } else { + keys.insert(key) + } + } + return Array(keys) + } + + func conflicts(with written: Set) -> Bool { + written.contains { key in reads.contains(key) || prefixes.contains { key.hasPrefix($0) } } + } + } + + /// Signalled when the gated transaction has run its body and waits to validate and commit. + let entered = DispatchSemaphore(value: 0) + /// Lets the gated transaction validate and commit. + let proceed = DispatchSemaphore(value: 0) + private let lock = NSLock() + private var entries: [String: Data] = [:] + /// The keys each commit wrote, by the version it produced. + private var commits: [(version: Int, keys: Set)] = [] + private var version = 0 + private var gateNext = false + + /// Pauses the next transaction after its body, before it validates and commits. + func gate() { + lock.lock() + defer { + lock.unlock() + } + gateNext = true + } + + func transaction(_ body: (any ExchangeEventSequencer.Transaction) throws -> R) throws -> R { + lock.lock() + var gated = gateNext + gateNext = false + lock.unlock() + while true { + lock.lock() + let attempt = Attempt(snapshot: entries) + let start = version + lock.unlock() + let result = try body(attempt) + if gated { + gated = false + entered.signal() + proceed.wait() + } + lock.lock() + defer { + lock.unlock() + } + // Only the commits after this attempt's snapshot, newest first. + let later = commits.reversed().prefix { $0.version > start } + guard !later.contains(where: { attempt.conflicts(with: $0.keys) }) else { + continue + } + for (key, value) in attempt.writes { + entries[key] = value + } + version += 1 + commits.append((version, Set(attempt.writes.keys))) + return result + } + } +} From 77e8b20454124c209865f9900e84e468df537d22 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 11:11:42 +0200 Subject: [PATCH 019/220] Pin the Per-Call Note Dedup and Clarify the Storage Retry Wording Closes two nits from the G1 fix verification. Test: a storage may discard an attempt and run a transaction's body again (clause wording in ExchangeLedgerStorage.md). HoldRegistry.beginReserving dedups the notes per reserve call, so an attempt that re-runs and returns the same handle notes it once; nothing pinned that. The new test ExchangeEventHoldTests.retriedReserveNotesOnce goes through a test-only RetryingStorage that runs the next transaction's body once, discards that attempt, then runs it again and commits. Both attempts reuse one reservation; after releasing, the registry no longer holds the handle and the reservation is gone. Ported from the G1 fix-verification probe (g1fv-probe/G1FixVerifyNotesProbeTests.swift, rerunAttemptNotesOnce). Mutation proof: beginReserving counting every attempt (`for handle in handles { notes.handles.insert(handle); reserving[handle, default: 0] += 1 }`) fails exactly this test, 7/8 of ExchangeEventHoldTests passing, with "Fixtures.isHeld(first[request]?.handle, by: sequencer) -> false: nothing stays noted after the retried call" and "the release removes the reservation". Reverted; the suite passes 8/8. Docs: "its bodies have no effect outside the transaction that outlasts the call" (ExchangeEventSequencer.Storage.transaction and ExchangeLedgerStorage.md) read as if the transaction outlasted the call. It now says the bodies have no effect outside the transaction "other than process-memory notes that end when the call returns". The Holds section now says "every backend above in its primary form", because the SQL row also admits overlapping serializable transactions, which the next sentence treats separately. Output unchanged: no source behaviour changed (doc comments and a test only); all 43 goldens and the G17 table pass unchanged. Gates: - GroveHealthKitFHIR macOS: Passed, 266 total, 264 passed, 2 skipped (same 2 skips as at 35f68942), 0 failed. - GroveFHIR macOS: Passed, 103/103. - GroveSensorKitFHIR macOS: Passed, 83/83. - GroveQuestionnaire macOS: Passed, 260/260. - GROVE_LOWERED_DEPLOYMENT_TARGETS=1 xcrun swift build --target GroveFHIRContract: Build complete. - swiftlint lint --strict --quiet (GroveFHIRContract, GroveHealthKitFHIR, GroveHealthKitFHIRTests, GroveFHIRTests): no findings. - reuse lint: compliant (2873/2873). Co-Authored-By: Claude Opus 5.5 --- .../ExchangeEventSequencer.swift | 5 +- .../ExchangeLedgerStorage.md | 4 +- .../ExchangeEventHoldTests.swift | 48 +++++++++++++++++++ 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift index 67a5941c3..ef472fe35 100644 --- a/Sources/GroveFHIRContract/ExchangeEventSequencer.swift +++ b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift @@ -35,8 +35,9 @@ public final class ExchangeEventSequencer: Sendable { /// Runs `body` as one transaction and returns its result. /// /// The transaction is valid only inside `body`. Grove never calls `transaction` from inside `body`, - /// and its bodies have no effect outside the transaction that outlasts the call, so a storage may - /// discard an attempt and run `body` again. A `body` that throws commits nothing. + /// and its bodies have no effect outside the transaction other than process-memory notes that end + /// when the call returns, so a storage may discard an attempt and run `body` again. A `body` that + /// throws commits nothing. func transaction(_ body: (any Transaction) throws -> R) throws -> R } diff --git a/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md b/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md index 2a16630e1..7f1806b1f 100644 --- a/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md +++ b/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md @@ -45,7 +45,7 @@ What Grove promises a storage in return: - Keys are ASCII from `[A-Za-z0-9_/-]` and at most 64 bytes: `producer`, `event/` and `facts/`. - Values are UTF-8 JSON, typically under 1 KiB; accept values up to 1 MiB, as facts grow with the number of studies. -- Grove never nests transactions, never lets a transaction escape its body, and its bodies have no effect outside the transaction that outlasts the call, so a storage may discard an attempt and run the body again. +- Grove never nests transactions, never lets a transaction escape its body, and its bodies have no effect outside the transaction other than process-memory notes that end when the call returns, so a storage may discard an attempt and run the body again. - `keys(prefixedBy:)` is called only by ``ExchangeEventSequencer/reset()`` and ``ExchangeEventSequencer/forgetReservations(madeBefore:)``. - One storage holds one ledger and nothing else. @@ -77,7 +77,7 @@ Both the cutoff and the stored instants are on the caller's clock, so choose one The entries hold no per-call state. Live calls are tracked in process memory: when the last call in the process that holds an event finishes and any of them released it, the event's reservation is removed, and otherwise it stays for the redelivery. A reserve notes the reservations its transaction returns from inside that transaction until it holds them, and the removing transaction checks those notes and the holds, so a release never removes a reservation another call in the process holds or is about to hold, whichever storage object, value or sequencer either call goes through. -This relies on the storage running one process's transactions one at a time, as every backend above does with its lock or a transaction that takes the write lock when it begins. +This relies on the storage running one process's transactions one at a time, as every backend above in its primary form does with its lock or a transaction that takes the write lock when it begins. A storage whose serializable transactions overlap, such as one that validates optimistically, still never reuses a sequence, but there a release can remove a reservation that a concurrent call has just reused, and that call's redelivery then becomes a new event, a duplicate and never a reuse. A release only ever removes the exact reservation its call made, never a successor's or one from before a reset. The one exception is a retraction's receipt: on release it forgets each deleted record's active reservation, whatever that reservation is, because no export will release it once the record is gone. diff --git a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldTests.swift b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldTests.swift index 5bdb3ae14..5e0d121d3 100644 --- a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldTests.swift +++ b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldTests.swift @@ -11,6 +11,40 @@ import Foundation import Testing +/// Runs the next transaction's body once and discards that attempt, then runs the body again and commits it: what a +/// storage that retries a conflicting attempt does. +private final class RetryingStorage: ExchangeEventSequencer.Storage, @unchecked Sendable { // `retryNext` is guarded by `lock`. + private struct Discarded: Error {} + + let base = ExchangeEventSequencer.InMemoryStorage() + private let lock = NSLock() + private var retryNext = false + + /// Discards the next transaction's first attempt. + func retry() { + lock.lock() + defer { + lock.unlock() + } + retryNext = true + } + + func transaction(_ body: (any ExchangeEventSequencer.Transaction) throws -> R) throws -> R { + lock.lock() + let retrying = retryNext + retryNext = false + lock.unlock() + if retrying { + _ = try? base.transaction { transaction -> R in + _ = try body(transaction) + throw Discarded() + } + } + return try base.transaction(body) + } +} + + /// Holds, releases, lapses and the receipts' transaction budget. @Suite struct ExchangeEventHoldTests { @@ -77,6 +111,20 @@ struct ExchangeEventHoldTests { #expect(!Fixtures.isHeld(winner[request]?.handle, by: sequencer)) } + @Test("G9: a reserve whose body the storage runs twice notes each reservation once; the release removes it") + func retriedReserveNotesOnce() throws { + let storage = RetryingStorage() + let sequencer = Fixtures.sequencer(storage) + let request = Fixtures.request("a") + let first = try sequencer.reserve([request], at: Fixtures.instant, facts: Fixtures.facts()) + storage.retry() + let again = try sequencer.reserve([request], at: Fixtures.instant, facts: Fixtures.facts()) + #expect(again == first, "both attempts reuse the reservation") + try sequencer.finish(first.values.map(\.handle) + again.values.map(\.handle), released: true, forgetting: []) + #expect(!Fixtures.isHeld(first[request]?.handle, by: sequencer), "nothing stays noted after the retried call") + #expect(try !Self.isReserved(request, in: storage.base), "the release removes the reservation") + } + @Test("G10: a handle from before a reset releases nothing, and a replaced reservation is not removed") func releaseIsOwned() throws { let storage = ExchangeEventSequencer.InMemoryStorage() From 55b9fc505261791b19aa43323688f192d6ef1d1e Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 11:49:24 +0200 Subject: [PATCH 020/220] State a Sample's Writer Only When the Caller Classifies Its Source Fix-round step G2 (final-spec (c) 3.1/3.2, (g) step 4, tests W1-W4 of (f), fingerprint 2.4). HKSourceRevision does not say whether a source is an application or a device, and the pinned HealthKit guide forbids classifying it from the identifier's shape, the source name or productType (ig-pin healthkit/input/pagecontent/mapping.md:142-143); only the caller's classification states a writer, and the author's name, identifier and version are copied from that sample's HKSourceRevision (:136-137, :144). Closes (rework-inputs/audit/ledger.md): - 3, confirmed finding 1 (major): the .automatic default classified sources by hasPrefix("com.apple.health."). Deleted; the default is .omit. - 4, confirmed finding 2 (minor, both directions): the recording Device now exists only when RecordingDevicePolicy resolved one from HKDevice, so recordingDeviceOmitted fires exactly when an HKDevice was declined (never next to a resolved or source-derived Device, never lost for a declined one). - 3, confirmed finding 8, HealthKitWriter docs: the .device doc that contradicted inference and the "is an application" / "This is the default" sentences are gone. API: - WriterPolicy = .omit (default) | .applications(Set) | .classify(@Sendable (HKSource) -> HealthKitWriter); it loses Hashable (it holds a closure). HealthKitWriter = .application | .omit. - HealthKitFHIRExporter.Options.writer and HealthKitConversionOptions.writer default to .omit, and with them HealthKitAssembly's default request options and the retraction request options. - Deleted: WriterPolicy.automatic/.application/.device, HealthKitWriter.device, ExchangeWriterDraft.recordingDevice and the assembler branch that made the recording Device the author, SourceFacts.recordingDevice(fromAppleSource:) and its call, HealthKitConverter.appleDeviceSourcePrefix. What RecordingDevicePolicy states from HKDevice is unchanged. - Context fingerprint writer part: ["omit"] | ["applications", , ] | ["classify"], by an exhaustive switch. The count keeps the length-framed sequence unambiguous; byte order keeps it independent of insertion order and collation. - HealthKitAssembly.outputRevision 1 -> 2. ExchangeGraphAssembler's stays 1: the deleted draft case had no other producer, so the assembler emits the same bytes for every draft that still exists. - Docs: WriterPolicy, HealthKitWriter, HealthKitConversionOptions.writer, TheConversionGraph.md, ConfiguringAConversion.md, and a short note in the GroveHealthKitFHIR.md exporter recipe on classifying sources. Output diff (goldens regenerated through TEST_RUNNER_GROVE_GOLDEN_OUTPUT_DIR outside the worktree, compared token-losslessly, then copied). Every change is in the allowed class: the writer application Device and its writer host Device are removed, the Provenance author agent is removed, nothing else in any graph changes (all other entries, entry order, references and warnings identical; no dangling reference). Changed because the fixture relied on the default writer (foreign writer org.example.writer, now unclassified): - bundled-patient-subject: $.entry[5] removed: Device urn:uuid:27bc90ae-3192-5159-990d-4764c5569192 (writer host, grove-host-device) $.entry[6] removed: Device urn:uuid:dafff25f-7b2a-50f1-8062-35eaaa6d3c23 (writer application, healthkit-application-device) $.entry[7->5].resource.entity[0].agent removed: [author -> urn:uuid:dafff25f-7b2a-50f1-8062-35eaaa6d3c23] (the removed writer application) - electrocardiogram: $.entry[5] removed: Device urn:uuid:659ba41a-b773-5177-9923-8a596c45de30 (writer host, grove-host-device) $.entry[6] removed: Device urn:uuid:ac9e967e-1606-58e5-8a33-72e6f7e602af (writer application, healthkit-application-device) $.entry[7->5].resource.entity[0].agent removed: [author -> urn:uuid:ac9e967e-1606-58e5-8a33-72e6f7e602af] (the removed writer application) - electrocardiogram-symptom-companion: $.entry[4] removed: Device urn:uuid:342152e5-0fa1-578f-ae92-0d3bc245ea35 (writer host, grove-host-device) $.entry[5] removed: Device urn:uuid:7cdf03d0-e248-5b92-901d-299e17845605 (writer application, healthkit-application-device) $.entry[6->4].resource.entity[0].agent removed: [author -> urn:uuid:7cdf03d0-e248-5b92-901d-299e17845605] (the removed writer application) - electrocardiogram-with-symptom: $.entry[5] removed: Device urn:uuid:08844702-36cb-57ff-b249-2b1b843fb79f (writer host, grove-host-device) $.entry[6] removed: Device urn:uuid:965a804c-2f33-5fe0-ae1e-a4a328007269 (writer application, healthkit-application-device) $.entry[7->5].resource.entity[0].agent removed: [author -> urn:uuid:965a804c-2f33-5fe0-ae1e-a4a328007269] (the removed writer application) - gateway-application-role: $.entry[5] removed: Device urn:uuid:48aeeb20-6643-5b41-b3a3-44093a548f15 (writer host, grove-host-device) $.entry[6] removed: Device urn:uuid:480efa67-eb12-5f15-92ba-fbc30cf24d40 (writer application, healthkit-application-device) $.entry[7->5].resource.entity[0].agent removed: [author -> urn:uuid:480efa67-eb12-5f15-92ba-fbc30cf24d40] (the removed writer application) - gateway-role: $.entry[4] removed: Device urn:uuid:1f896505-6996-55e4-8231-8412a4c864a8 (writer host, grove-host-device) $.entry[5] removed: Device urn:uuid:1fb8e303-b58a-5107-ac2d-9ddced20bb00 (writer application, healthkit-application-device) $.entry[6->4].resource.entity[0].agent removed: [author -> urn:uuid:1fb8e303-b58a-5107-ac2d-9ddced20bb00] (the removed writer application) - heartbeat-series: $.entry[4] removed: Device urn:uuid:35f19e6b-6e60-5b6c-b203-d4ac0dce18aa (writer host, grove-host-device) $.entry[5] removed: Device urn:uuid:f72582bb-3a7c-5255-808c-cdba39fd1a84 (writer application, healthkit-application-device) $.entry[6->4].resource.entity[0].agent removed: [author -> urn:uuid:f72582bb-3a7c-5255-808c-cdba39fd1a84] (the removed writer application) - native-identifier-disclosure: $.entry[4] removed: Device urn:uuid:51571f65-d367-5848-9557-f958f42357bc (writer host, grove-host-device) $.entry[5] removed: Device urn:uuid:647ca0a1-1154-58d5-bb7c-a880387bbbcb (writer application, healthkit-application-device) $.entry[6->4].resource.entity[0].agent removed: [author -> urn:uuid:647ca0a1-1154-58d5-bb7c-a880387bbbcb] (the removed writer application) - two-study-enrollments: $.entry[10] removed: Device urn:uuid:2a8208fd-d3b8-5a36-8e6c-fe64275ae3da (writer host, grove-host-device) $.entry[11] removed: Device urn:uuid:e34dda89-a30e-5394-b8ee-b0595e1dd7c7 (writer application, healthkit-application-device) $.entry[12->10].resource.entity[0].agent removed: [author -> urn:uuid:e34dda89-a30e-5394-b8ee-b0595e1dd7c7] (the removed writer application) - udi-disclosure: $.entry[4] removed: Device urn:uuid:590dd017-f9f1-5627-abdc-b1f47959e10e (writer host, grove-host-device) $.entry[5] removed: Device urn:uuid:4f6c6282-7153-5005-8765-7a6ad1ac2428 (writer application, healthkit-application-device) $.entry[6->4].resource.entity[0].agent removed: [author -> urn:uuid:4f6c6282-7153-5005-8765-7a6ad1ac2428] (the removed writer application) - workout-route: $.entry[4] removed: Device urn:uuid:18fba38a-2ee6-5140-80f2-d84f938266b4 (writer host, grove-host-device) $.entry[5] removed: Device urn:uuid:d21d9031-3216-5431-b57f-1b2afa147c46 (writer application, healthkit-application-device) $.entry[6->4].resource.entity[0].agent removed: [author -> urn:uuid:d21d9031-3216-5431-b57f-1b2afa147c46] (the removed writer application) - writer-device-classification.json -> writer-omitted.json: $.entry[4].resource.entity[0].agent removed: [author -> urn:uuid:4d25df34-97c0-5441-a4e4-74e7de79ed10] (the recording Device, which stays) - writer-device-classification-without-recording-device.json -> writer-omitted-without-recording-device.json: renamed only, byte-identical (the .device classification it pinned no longer exists; under .omit it states exactly what it stated before). - outlines.json: per changed case above, the two removed Device entries leave its outline (same fullUrls and identifiers as listed); the two writer-device-classification keys become writer-omitted and writer-omitted-without-recording-device with identical outlines; all warnings unchanged. Unchanged (byte-identical): the 14 observation shapes, clinical-document, the 5 retractions, repository-ids-on-every-node and the writer cases writer-foreign-application, writer-self-build-equals-revision, writer-self-older-build, writer-self-token-identical, writer-host-equals-converter-host, writer-blank-name-with-sync-identity, writer-without-version, sync-identity. These cases pin how a classified writer travels (repository-ids-on-every-node names the writer nodes), so their fixtures now pass .application explicitly; no other fixture changed. G17: the 13 changed files carry healthKit: 2 with their new digests; the byte-identical rename keeps healthKit: 1 under its new name. Tests: - New HealthKitFHIRExporterWriterTests: W1 exporter default (an Apple per-device source com.apple.health., "Lukas's Apple Watch", without HKDevice / with a declined HKDevice / with a resolved one: no writer, no author, no Device naming the source, the HKDevice's recording Device only when resolved, the warning only when declined) and W1 through HealthKitConversionOptions() and .default; W2 .applications (listed source states name, bundle id and version from HKSourceRevision and is the author, byte-equal to the entry point under .application; unlisted and Apple sources state nothing); W3 .classify (closure asked per source, .application states the revision's values, .omit nothing); W4 scans Sources/GroveHealthKitFHIR for the literal "com.apple.health. (and `grep -rn '"com.apple.health.' Sources/GroveHealthKitFHIR` finds nothing). - Fingerprint: G3 perturbations are now writer applications, a second member, an empty set and classify; a writer-policy change gives a reserved record sequences 1, 2, 3 across omit -> applications -> omit; equal application sets built in different insertion orders (iteration orders checked to differ) fingerprint equally, a member less does not. - Deleted automaticWriterClassifiesAppleDeviceSources (W1-W4 replace it). deviceSourceReusesRecordingDevice becomes "an unclassified source keeps the recording Device its HKDevice names, and the Provenance names no author". Test-helper writer defaults (HealthKitConversionContext test init, HealthKitDeviceIdentityTests) follow production to .omit; the tests that need a writer (invalidWriterBundleIdentifierIsRefused, converterReadsTheStoredFacts) pass .application. Mutation proof (each applied alone, full GroveHealthKitFHIRTests run, reverted; the pristine files compared equal afterwards): - (a1) Options.writer default .classify { _ in .application }: fails W1 exporter default, G3 (classify equals base), graphsEqualReference, heartbeatSeriesRecord, authorizedWorkoutRouteRecord (5 failed). - (a2) HealthKitConversionOptions writer default .application: fails W1 conversion options, healthKitOptionDefaults, matchesCheckedInGolden, documentGraphsOmitTheGatewayApplication, graphsEqualReference, the heartbeat and route record tests (7 failed). - (b) .applications ignoring membership: fails W2 (org.example.other stated and named as author). - (c) .classify result ignored (closure called, .application returned): fails W3 (org.example.other stated and named as author). - (d) recording Device derived from a com.apple.health. source again: fails W1 (both) and W4 (3 failed). - (e) recordingDeviceOmitted appended next to a resolved Device: fails W1 (both), "A conversion reports exactly what the graph lost", matchesCheckedInGolden, graphsEqualReference (5 failed). - (f) applications fingerprint parts left unsorted: fails the insertion-order fingerprint test. Gates: - GroveHealthKitFHIR macOS: Passed, 272 total, 270 passed, 2 skipped (the same 2 as before), 0 failed. - GroveFHIR macOS: Passed, 103/103. - GroveSensorKitFHIR macOS: Passed, 83/83. - GroveQuestionnaire macOS: Passed, 260/260. - GROVE_LOWERED_DEPLOYMENT_TARGETS=1 xcrun swift build --target GroveFHIRContract: Build complete. - swiftlint lint --strict --quiet (GroveFHIRContract, GroveHealthKitFHIR, GroveHealthKitFHIRTests, GroveFHIRTests): no findings. - reuse lint: compliant (2874/2874). - Scripts/validate-fhir-conformance.sh healthkit: "OK - all healthkit resources conform to their declared R4 profiles" (28 resources), contract generator and semantic-vector checks clean. Guides: a scratchpad copy of the read-only ig-pin extract with mobile, sensor and healthkit built from it (0 unsuppressed errors or warnings); the extract has no git history, so the copy was git-initialized and GROVE_FHIR_REF pointed at that commit. - xcodebuild docbuild GroveHealthKitFHIR: succeeded; no new warning in GroveHealthKitFHIR or GroveFHIRContract (the unused public HealthKit import warning in the Options file is gone, as WriterPolicy now exposes HKSource). Size (A): code 11,143 (+1,438), public 1,006 (+133) (vs baseline Grove 9b086e60; vs parent 77e8b204: code -29, public -4. Level B: code 21,205 (+1,438), public 1,909 (+133).) Co-Authored-By: Claude Opus 5.5 --- .../ExchangeGraphAssembler+Devices.swift | 8 +- .../ExchangeGraphDraft.swift | 4 +- .../ConfiguringAConversion.md | 2 +- .../GroveHealthKitFHIR.md | 3 + .../TheConversionGraph.md | 3 +- .../HealthKitAssembly+SourceFacts.swift | 25 -- .../HealthKitAssembly.swift | 2 +- .../HealthKitConversionContext.swift | 3 +- .../HealthKitConverter.swift | 3 - .../HealthKitFHIRDisclosurePolicies.swift | 21 +- .../HealthKitFHIRExporter+Fingerprint.swift | 18 +- .../HealthKitFHIRExporter+Options.swift | 42 +- .../GoldenGraphCases.swift | 36 +- .../GoldenGraphFixtures.swift | 8 + .../GoldenGraphTests.swift | 6 +- .../GoldenOutputRevisionTests.swift | 28 +- .../HealthKitDeviceIdentityTests.swift | 18 +- ...ealthKitFHIRExporterFingerprintTests.swift | 38 +- .../HealthKitFHIRExporterTests.swift | 30 -- .../HealthKitFHIRExporterWriterTests.swift | 242 +++++++++++ .../HealthKitFHIRTestContext.swift | 2 +- .../ProducerAlignmentTests.swift | 4 +- .../Goldens/bundled-patient-subject.json | 152 ------- .../electrocardiogram-symptom-companion.json | 152 ------- .../electrocardiogram-with-symptom.json | 152 ------- .../Resources/Goldens/electrocardiogram.json | 152 ------- .../Goldens/gateway-application-role.json | 152 ------- .../Resources/Goldens/gateway-role.json | 152 ------- .../Resources/Goldens/heartbeat-series.json | 152 ------- .../Goldens/native-identifier-disclosure.json | 152 ------- .../Resources/Goldens/outlines.json | 393 ++++-------------- .../Goldens/two-study-enrollments.json | 152 ------- .../Resources/Goldens/udi-disclosure.json | 152 ------- .../Resources/Goldens/workout-route.json | 152 ------- ...ter-omitted-without-recording-device.json} | 0 ...lassification.json => writer-omitted.json} | 16 - .../StoredSampleFixturesTests.swift | 2 +- 37 files changed, 470 insertions(+), 2159 deletions(-) create mode 100644 Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterWriterTests.swift rename Tests/GroveHealthKitFHIRTests/Resources/Goldens/{writer-device-classification-without-recording-device.json => writer-omitted-without-recording-device.json} (100%) rename Tests/GroveHealthKitFHIRTests/Resources/Goldens/{writer-device-classification.json => writer-omitted.json} (96%) diff --git a/Sources/GroveFHIRContract/ExchangeGraphAssembler+Devices.swift b/Sources/GroveFHIRContract/ExchangeGraphAssembler+Devices.swift index f370469b3..220ef252d 100644 --- a/Sources/GroveFHIRContract/ExchangeGraphAssembler+Devices.swift +++ b/Sources/GroveFHIRContract/ExchangeGraphAssembler+Devices.swift @@ -84,12 +84,8 @@ extension ExchangeGraphAssembler { if draft.repositoryIDs[.writerHost] != nil, !writerEntries.contains(where: { $0 == writer?.host.identity }) { throw ExchangeAssemblyError.repositoryIDWithoutNode(.writerHost) } - let authorURL: String? = switch draft.writer { - case .application: writer?.applicationURL - case .recordingDevice: recording?.url - case nil: nil - } - return Devices(converter: converter, recording: recording, writer: writer, authorURL: authorURL) + // The writer application is the Provenance author; without one the Provenance names none. + return Devices(converter: converter, recording: recording, writer: writer, authorURL: writer?.applicationURL) } private func converterSnapshots( diff --git a/Sources/GroveFHIRContract/ExchangeGraphDraft.swift b/Sources/GroveFHIRContract/ExchangeGraphDraft.swift index bb671320c..66b891bd5 100644 --- a/Sources/GroveFHIRContract/ExchangeGraphDraft.swift +++ b/Sources/GroveFHIRContract/ExchangeGraphDraft.swift @@ -184,13 +184,11 @@ package struct ExchangeRecordingDeviceDraft: Sendable { } -/// Who wrote the record into the source store, as the Provenance author. +/// Who wrote the record into the source store, as the Provenance author; a draft without one names no author. package enum ExchangeWriterDraft: Sendable { /// An application and the host it ran on, stated as snapshots of their own; `statesVersion` is /// false when the source named no version, so the Device carries none. case application(ApplicationDevice, host: HostDevice, statesVersion: Bool) - /// The graph's recording Device authored the record; nothing is stated without one. - case recordingDevice } diff --git a/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/ConfiguringAConversion.md b/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/ConfiguringAConversion.md index 29a70903e..60d500c43 100644 --- a/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/ConfiguringAConversion.md +++ b/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/ConfiguringAConversion.md @@ -18,7 +18,7 @@ The Grove Mobile implementation guide (`https://grovealliance.org/fhir/mobile`) A conversion context is an event record, not a bag of defaults. The shared `ExchangeEventContext` carries the subject, the producer instance and monotonic event sequence, the converting application and its host, the deployment's identity scope, the source repository scope, and the conversion instant. -``HealthKitConversionOptions`` adds the HealthKit-specific choices: which writer the source revision names, how a sample's `HKDevice` resolves to a recording device, and which disclosures the deployment authorizes. +``HealthKitConversionOptions`` adds the HealthKit-specific choices: whether the source revision's writer is stated (only when you classify it as an application; by default it is omitted), how a sample's `HKDevice` resolves to a recording device, and which disclosures the deployment authorizes. Construct and persist the event inputs before conversion; an exact retry reuses them unchanged. ```swift diff --git a/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/GroveHealthKitFHIR.md b/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/GroveHealthKitFHIR.md index 7548bb050..995fcf154 100644 --- a/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/GroveHealthKitFHIR.md +++ b/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/GroveHealthKitFHIR.md @@ -93,6 +93,9 @@ let exporter = try HealthKitFHIRExporter( ) ``` +The exporter states the application that wrote a sample only for sources you classify: HealthKit does not say whether a source is an application or a device, so by default no writer is stated. +Pass the bundle identifiers you know to be applications as `options.writer = .applications(...)`, or classify each source with `.classify`; see ``HealthKitFHIRExporter/WriterPolicy``. + Export a batch and store each graph's bytes verbatim. Release the receipt only once the stored graphs and the HealthKit anchor are durably committed; until then an exact redelivery reproduces the same events, byte for byte. diff --git a/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/TheConversionGraph.md b/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/TheConversionGraph.md index 4cd91572f..254d0fcf2 100644 --- a/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/TheConversionGraph.md +++ b/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/TheConversionGraph.md @@ -60,7 +60,8 @@ Each is an immutable event-time snapshot; an application links to its host throu A HealthKit application Device claims the HealthKit application profile and carries exactly two identifiers: the opaque event-scoped `device-snapshot`, plus the clear Apple product bundle identifier typed as `healthkit-identifier-type#apple-bundle-id`. That clear value identifies an application product, never an installation, host, account, or person. The converter always uses this shape; the writer of an `HKSourceRevision` uses it only when the caller classifies the source as an application through ``HealthKitWriter``. -That writer snapshot and the host it ran on are the graph's `writer` and `writerHost` nodes, the source agent of the Provenance; a writer classified as a device is the recording Device itself. +That writer snapshot and the host it ran on are the graph's `writer` and `writerHost` nodes, the source agent of the Provenance. +HealthKit does not say whether a source is an application or a device, so a source the caller has not classified states no writer and the Provenance names no author; Grove never infers the classification from the bundle identifier, the source name or the product type. A writer snapshot the converter already states, such as the phone the converter runs on, is that one entry rather than a second one. A recording Device carries two identities. diff --git a/Sources/GroveHealthKitFHIR/HealthKitAssembly+SourceFacts.swift b/Sources/GroveHealthKitFHIR/HealthKitAssembly+SourceFacts.swift index 415606233..0df3bf648 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitAssembly+SourceFacts.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitAssembly+SourceFacts.swift @@ -41,9 +41,6 @@ extension HealthKitAssembly { warnings.append(.recordingDeviceOmitted(deviceName: healthKitDevice.name?.nonBlank)) } } - if recordingDevice == nil, options.writer == .device { - recordingDevice = Self.recordingDevice(fromAppleSource: revision) - } self.recordingDevice = recordingDevice self.writer = try Self.writer(revision, classification: options.writer) self.nativeIdentifiers = [options.nativeIdentifierDisclosure.identifier(for: sample.uuid.uuidString.lowercased())].compactMap(\.self) @@ -85,26 +82,6 @@ extension HealthKitAssembly.SourceFacts { return ExchangeRecordingDeviceDraft(device: recorder, resource: device) } - /// The physical unit an Apple per-device source stands for, when the sample carries no `HKDevice` - /// with a stable token: the source's per-device bundle identifier is that token. Any other source - /// yields nothing; its manufacturer and model are not known. - private static func recordingDevice(fromAppleSource revision: HKSourceRevision) -> ExchangeRecordingDeviceDraft? { - let bundleIdentifier = revision.source.bundleIdentifier - guard bundleIdentifier.hasPrefix(HealthKitConverter.appleDeviceSourcePrefix), - let recorder = try? RecordingDevice( - stableUnitToken: bundleIdentifier, - name: revision.source.name.nonBlank, - manufacturer: "Apple Inc.", - modelNumber: revision.productType?.nonBlank - ) else { - return nil - } - return ExchangeRecordingDeviceDraft( - device: recorder, - resource: recordingDevice(name: recorder.name, manufacturer: recorder.manufacturer, modelNumber: recorder.modelNumber) - ) - } - private static func recordingDevice(name: String?, manufacturer: String?, modelNumber: String?) -> Device { var device = Device() device.meta = Meta(profile: [Profile.groveRecordingDevice]) @@ -127,8 +104,6 @@ extension HealthKitAssembly.SourceFacts { switch classification { case .omit: return nil - case .device: - return .recordingDevice case .application: guard let name = revision.source.name.nonBlank, let bundleIdentifier = revision.source.bundleIdentifier.nonBlank else { diff --git a/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift b/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift index 6dd8c2e5c..1a297d96c 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift @@ -62,7 +62,7 @@ struct HealthKitAssembly: Sendable { /// The revision of the graphs this adapter's assembly builds. Bump it whenever the bytes it emits can /// change for equal inputs: it enters every exporter's context fingerprint, so an event reserved under an /// older revision is never redelivered under the same identifier with different bytes. - static let outputRevision: UInt = 1 + static let outputRevision: UInt = 2 static let adapter = ExchangeAdapterContract( adapterID: "healthkit", diff --git a/Sources/GroveHealthKitFHIR/HealthKitConversionContext.swift b/Sources/GroveHealthKitFHIR/HealthKitConversionContext.swift index ac34da2af..9fa843de8 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConversionContext.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConversionContext.swift @@ -45,6 +45,7 @@ public struct HealthKitConversionOptions: Sendable { /// Every policy omits. public static let `default` = Self() + /// How every sample's source is stated: by default not at all, as nothing classified it. See ``HealthKitWriter``. public var writer: HealthKitWriter public var recordingDevice: any RecordingDeviceResolver public var udiDisclosure: HealthKitUDIDisclosurePolicy @@ -52,7 +53,7 @@ public struct HealthKitConversionOptions: Sendable { public var nativeIdentifierDisclosure: GovernedSourceIdentifierDisclosurePolicy public init( - writer: HealthKitWriter = .application, + writer: HealthKitWriter = .omit, recordingDevice: any RecordingDeviceResolver = .healthKitLocalIdentifier, udiDisclosure: HealthKitUDIDisclosurePolicy = .omit, routeDisclosure: RouteDisclosurePolicy = .omit, diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter.swift index 88c0875dc..ab938ce39 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter.swift @@ -77,9 +77,6 @@ public struct HealthKitConverter: Sendable { extension HealthKitConverter { /// The closed adapter token every HealthKit identity preimage carries. static let adapterID = "healthkit" - /// The bundle-identifier prefix of HealthKit's per-device sources: the watch or phone that recorded a - /// sample itself, as `com.apple.health.`. - static let appleDeviceSourcePrefix = "com.apple.health." /// The catalog-driven reason a sample without a binding fails closed. static func unconvertibleSampleError(for type: HealthKitSourceType) -> HealthKitConversionError { diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRDisclosurePolicies.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRDisclosurePolicies.swift index f6a01482b..963b677f0 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRDisclosurePolicies.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRDisclosurePolicies.swift @@ -22,22 +22,17 @@ public enum HealthKitUDIDisclosurePolicy: Hashable, Sendable { } -/// Interpretation of `HKSourceRevision.source` for one conversion. +/// How the caller classifies the source (`HKSourceRevision.source`) of one sample. /// -/// Which application wrote a sample is provenance a study needs — a weight from a connected scale -/// is different evidence from one typed in by hand — so the writer is always recorded. An -/// `HKSource` always carries a bundle identifier and is an application; hardware attribution is -/// `HKDevice`, which the recording device carries separately. +/// HealthKit does not say whether a source is an application or a device, so the classification is the +/// caller's: Grove never infers it from the bundle identifier, the source name or the product type. Which +/// physical unit measured the sample is `HKDevice`, which the recording Device carries separately. public enum HealthKitWriter: Hashable, Sendable { - /// Record the writer as the application it is, with the host it ran on, as the graph's - /// `ExchangeGraphNode.writer` and `ExchangeGraphNode.writerHost` snapshots. This is the default. + /// The source is an application: it is stated with its name, bundle identifier and version, all copied + /// from the sample's `HKSourceRevision`, and the host it ran on, as the graph's `ExchangeGraphNode.writer` + /// and `ExchangeGraphNode.writerHost` snapshots and the Provenance author. case application - /// The caller has established that the source stands for a device rather than an application. - /// The Provenance author reuses the dual-identity recording Device when stable per-unit - /// evidence exists. Without that evidence, the Device author is omitted rather than inferred - /// from model, product, application, or record identifiers. - case device - /// The caller has not classified the source; no writer is stated and the Provenance names no author. + /// No writer is stated, and the Provenance names no author. case omit } diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift index 1cc5bd6ef..06eee406d 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift @@ -42,8 +42,8 @@ extension HealthKitFHIRExporter { /// A request's fingerprint is the SHA-256, base64url without padding, of the length-framed call parts /// followed by the record's own parts. A stored reservation is reused only under an equal fingerprint, so /// a Grove update that changes output, any option change, or another participant over the same ledger - /// never reuses an event identifier for other bytes. A custom ``RecordingDevicePolicy`` resolver enters - /// by its presence only; its behaviour is not fingerprinted. + /// never reuses an event identifier for other bytes. A ``WriterPolicy/classify(_:)`` closure and a custom + /// ``RecordingDevicePolicy`` resolver enter by their presence only; their behaviour is not fingerprinted. struct ExportContext: Sendable { /// The length-framed parts every request of this exporter starts with, in order. private let framedCallParts: Data @@ -124,12 +124,18 @@ extension Subject: ExchangeContextFingerprinted { @available(iOS 18, macOS 15, watchOS 11, *) extension HealthKitFHIRExporter.WriterPolicy: ExchangeContextFingerprinted { + /// The tag, then for an application set its count, which fixes how many parts follow, and its members in UTF-8 + /// byte order, so equal sets fingerprint equally whatever their insertion order or the platform's collation. A + /// closure enters by its presence only; how it classifies is the caller's to keep stable. var fingerprintParts: [String] { switch self { - case .automatic: ["automatic"] - case .application: ["application"] - case .device: ["device"] - case .omit: ["omit"] + case .omit: + return ["omit"] + case .applications(let bundleIdentifiers): + let sorted = bundleIdentifiers.sorted { $0.utf8.lexicographicallyPrecedes($1.utf8) } + return ["applications", String(sorted.count)] + sorted + case .classify: + return ["classify"] } } } diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift index cfe59b3f0..e530a68e9 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift @@ -27,8 +27,8 @@ extension HealthKitFHIRExporter { /// The HealthKit-specific choices of one exporter: how sources, devices and identifiers are stated, /// and which disclosures the deployment authorizes. Every disclosure defaults to omission. public struct Options: Sendable { - /// How the source that wrote a sample is stated. See ``WriterPolicy``. - public var writer: WriterPolicy = .automatic + /// How the source that wrote a sample is stated: by default not at all. See ``WriterPolicy``. + public var writer: WriterPolicy = .omit /// How the physical unit behind a sample's `HKDevice` is identified. See ``RecordingDevicePolicy``. public var recordingDevice: RecordingDevicePolicy = .localIdentifier /// How the converting application relates to each measurement. See ``RolePolicy``. @@ -49,32 +49,32 @@ extension HealthKitFHIRExporter { /// How `HKSourceRevision.source`, the app or device that wrote a sample into HealthKit, is stated. /// - /// The origin of a sample is always kept: an application becomes an application Device snapshot with - /// its bundle identifier and version plus the host it ran on; a physical device becomes a recording - /// Device with a stable, pseudonymous identity. The two shapes differ, so the exporter needs to know - /// which one a source is. - public enum WriterPolicy: Hashable, Sendable { - /// Apple's per-device sources (bundle identifiers `com.apple.health.`, i.e. a watch or - /// phone that recorded the sample itself) are physical devices; every other source is an application. - case automatic - /// Every source is stated as an application. - case application - /// Every source stands for the sample's physical device; the Provenance author is the recording Device. - case device - /// No writer is stated and the Provenance names no author. + /// `HKSourceRevision` does not say whether its source is an application or a device, and the HealthKit + /// guide forbids classifying it from the bundle identifier's shape, the source name or the product type: + /// a source nobody classified states no writer. Only the caller's explicit classification states one. The + /// physical unit a sample was measured on is the recording Device, which ``RecordingDevicePolicy`` + /// resolves from `HKDevice` whatever this policy says. + public enum WriterPolicy: Sendable { + /// No writer is stated, and the Provenance names no author. The default. case omit + /// A source whose bundle identifier is one of these, which the caller knows to be applications, is + /// stated as that application, with its name, bundle identifier and `HKSourceRevision.version` and + /// the host it ran on. Every other source states no writer. + case applications(Set) + /// The caller classifies each source. The closure must be a pure function of the source and stable + /// across application versions: the context fingerprint records only that a closure classifies, so + /// a closure whose answers change can restate a reserved event's writer differently on redelivery. + case classify(@Sendable (HKSource) -> HealthKitWriter) /// The classification of one source under this policy. func classification(of source: HKSource) -> HealthKitWriter { switch self { - case .automatic: - source.bundleIdentifier.hasPrefix(HealthKitConverter.appleDeviceSourcePrefix) ? .device : .application - case .application: - .application - case .device: - .device case .omit: .omit + case .applications(let bundleIdentifiers): + bundleIdentifiers.contains(source.bundleIdentifier) ? .application : .omit + case .classify(let classify): + classify(source) } } } diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift index c594ef745..900fab3c6 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift @@ -120,42 +120,45 @@ extension GoldenCase { } ] - /// Sequences 20-39: how the sample's writer (`HKSourceRevision`) travels. + /// Sequences 20-39: how the sample's writer (`HKSourceRevision`) travels once the caller classified its source as an + /// application, and what an unclassified source states. static let writers: [GoldenCase] = [ GoldenCase("writer-foreign-application", sequence: 20) { sequence in - try GoldenFixtures.convert(attributedHeartRate(uuid: 20, writer: GoldenFixtures.foreignWriter), sequence: sequence) + try GoldenFixtures.convert(attributedHeartRate(uuid: 20, writer: GoldenFixtures.foreignWriter), sequence: sequence, .applicationWriter) }, // The converter states version 1.2.3 build 42 and HealthKit records revision version 42: the shape a real // device produces. The tokens differ, so the writer travels as a second application Device of the same bundle. GoldenCase("writer-self-build-equals-revision", sequence: 21) { sequence in - var inputs = GoldenFixtures.Inputs() + var inputs = GoldenFixtures.Inputs.applicationWriter inputs.converter = GoldenFixtures.selfConverter(version: "1.2.3", build: "42") return try GoldenFixtures.convert(attributedHeartRate(uuid: 21, writer: GoldenFixtures.selfWriter(revisionVersion: "42")), sequence: sequence, inputs) }, GoldenCase("writer-self-older-build", sequence: 22) { sequence in - var inputs = GoldenFixtures.Inputs() + var inputs = GoldenFixtures.Inputs.applicationWriter inputs.converter = GoldenFixtures.selfConverter(version: "1.2.3", build: "43") return try GoldenFixtures.convert(attributedHeartRate(uuid: 22, writer: GoldenFixtures.selfWriter(revisionVersion: "42")), sequence: sequence, inputs) }, // No build and a version equal to the revision's: the only shape whose writer token equals the converter's. GoldenCase("writer-self-token-identical", sequence: 23) { sequence in - var inputs = GoldenFixtures.Inputs() + var inputs = GoldenFixtures.Inputs.applicationWriter inputs.converter = GoldenFixtures.selfConverter(version: "42", build: nil) return try GoldenFixtures.convert(attributedHeartRate(uuid: 23, writer: GoldenFixtures.selfWriter(revisionVersion: "42")), sequence: sequence, inputs) }, GoldenCase("writer-host-equals-converter-host", sequence: 24) { sequence in - var inputs = GoldenFixtures.Inputs() + var inputs = GoldenFixtures.Inputs.applicationWriter inputs.converterHost = try HostDevice(operatingSystemVersion: "26.1.0", name: "Phone", manufacturer: "Apple", modelNumber: "iPhone17,1") return try GoldenFixtures.convert(attributedHeartRate(uuid: 24, writer: GoldenFixtures.foreignWriter), sequence: sequence, inputs) }, - GoldenCase("writer-device-classification", sequence: 25) { sequence in + // An unclassified source states no writer and the Provenance no author; the recording Device the sample's + // `HKDevice` names stays. + GoldenCase("writer-omitted", sequence: 25) { sequence in var inputs = GoldenFixtures.Inputs() - inputs.options.writer = .device + inputs.options.writer = .omit return try GoldenFixtures.convert(attributedHeartRate(uuid: 25, writer: GoldenFixtures.foreignWriter), sequence: sequence, inputs) }, - GoldenCase("writer-device-classification-without-recording-device", sequence: 26) { sequence in + GoldenCase("writer-omitted-without-recording-device", sequence: 26) { sequence in var inputs = GoldenFixtures.Inputs() - inputs.options.writer = .device + inputs.options.writer = .omit return try GoldenFixtures.convert( GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(26), writer: GoldenFixtures.foreignWriter), sequence: sequence, @@ -165,15 +168,19 @@ extension GoldenCase { GoldenCase("writer-blank-name-with-sync-identity", sequence: 27) { sequence in var writer = GoldenFixtures.foreignWriter writer.name = "" - return try GoldenFixtures.convert(attributedHeartRate(uuid: 27, writer: writer, metadata: syncMetadata), sequence: sequence) + return try GoldenFixtures.convert(attributedHeartRate(uuid: 27, writer: writer, metadata: syncMetadata), sequence: sequence, .applicationWriter) }, GoldenCase("writer-without-version", sequence: 28) { sequence in var writer = GoldenFixtures.foreignWriter writer.version = nil - return try GoldenFixtures.convert(attributedHeartRate(uuid: 28, writer: writer), sequence: sequence) + return try GoldenFixtures.convert(attributedHeartRate(uuid: 28, writer: writer), sequence: sequence, .applicationWriter) }, GoldenCase("sync-identity", sequence: 29) { sequence in - try GoldenFixtures.convert(attributedHeartRate(uuid: 29, writer: GoldenFixtures.foreignWriter, metadata: syncMetadata), sequence: sequence) + try GoldenFixtures.convert( + attributedHeartRate(uuid: 29, writer: GoldenFixtures.foreignWriter, metadata: syncMetadata), + sequence: sequence, + .applicationWriter + ) } ] @@ -209,8 +216,9 @@ extension GoldenCase { inputs.studies = [.test("study-a"), .test("study-b")] return try GoldenFixtures.convert(attributedHeartRate(uuid: 45, writer: GoldenFixtures.foreignWriter), sequence: sequence, inputs) }, + // The writer and its host are nodes only once the source is classified as an application. GoldenCase("repository-ids-on-every-node", sequence: 46) { sequence in - var inputs = GoldenFixtures.Inputs() + var inputs = GoldenFixtures.Inputs.applicationWriter inputs.repositoryIDs = try Dictionary(uniqueKeysWithValues: [ (ExchangeGraphNode.bundle, "bundle-46"), (.primaryOutput, "output-46"), (.provenance, "provenance-46"), (.applicationDevice, "app-46"), (.hostDevice, "host-46"), (.recordingDevice, "recorder-46"), diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift index d48065f72..88e8f49fe 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift @@ -76,6 +76,14 @@ struct GoldenCase: Sendable, CustomTestStringConvertible { enum GoldenFixtures { /// What a case varies beyond its sample: every field defaults to the test context's fixed facts. struct Inputs: Sendable { + /// The default inputs with the sample's source classified as an application, for the cases that pin how a + /// writer travels; by default no writer is stated. + static var applicationWriter: Inputs { + var inputs = Inputs() + inputs.options.writer = .application + return inputs + } + var subject: Subject = .testPatient var converter: ApplicationDevice = .test var converterHost: HostDevice = .test diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift index bbf16d852..957b0bffe 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift @@ -235,14 +235,14 @@ struct GoldenGraphTests { #expect(provenance.target.count == 1) } - /// A writer whose bundle identifier is not one is a refusal; a writer with a blank name is merely no writer - /// (`writer-blank-name-with-sync-identity` pins that graph). + /// A writer classified as an application whose bundle identifier is not one is a refusal; a writer with a blank + /// name is merely no writer (`writer-blank-name-with-sync-identity` pins that graph). @Test func invalidWriterBundleIdentifierIsRefused() throws { var writer = GoldenFixtures.foreignWriter writer.bundleIdentifier = "not a bundle id" let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0xA1), writer: writer) - let context = try GoldenFixtures.context(sequence: 201) + let context = try GoldenFixtures.context(sequence: 201, .applicationWriter) #expect(throws: HealthKitConversionError.sourceApplicationInvalid) { try HealthKitConverter().convert(sample, context: context) } diff --git a/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift b/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift index 589e3ff11..cd35b7369 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift @@ -46,13 +46,13 @@ struct GoldenOutputRevisionTests { static let table: [GoldenRevision] = [ GoldenRevision("blood-pressure-correlation", digest: "Cw-NT44sFRCYAsIii_BZXdS6r0gD2D8dMbV1_DYSuLE", assembler: 1, healthKit: 1), GoldenRevision("body-mass-user-entered", digest: "SFo9ZdasPxzkAQI2AcW0vlziFfAJyl2L5c-t5eHJdNY", assembler: 1, healthKit: 1), - GoldenRevision("bundled-patient-subject", digest: "DdlaOOPCSIAMV1twtigLxjshiVzTqBaiO_YYaY-QOcA", assembler: 1, healthKit: 1), + GoldenRevision("bundled-patient-subject", digest: "5iDgaytn2G-8k0wh1P9Q3Ry4jMksyVJ-ayUGBchVbuM", assembler: 1, healthKit: 2), GoldenRevision("clinical-document", digest: "1asW-RkPmayr0J1cy__i-SxCb5c64dvfpMYFGkZdsOc", assembler: 1, healthKit: 1), - GoldenRevision("electrocardiogram-symptom-companion", digest: "kr9x4zg2fLjcx8pXVU1zrNAkyOeXZDrOoDLW3QPA188", assembler: 1, healthKit: 1), - GoldenRevision("electrocardiogram-with-symptom", digest: "9l2JtyHoAElz12UR_N0uGxnZo0YLw4X1vH-asSwgPfc", assembler: 1, healthKit: 1), - GoldenRevision("electrocardiogram", digest: "4O8qSuiYKdJHCH6i1nQLwaj9Wj_WTXNJQSvGaTa4TZc", assembler: 1, healthKit: 1), - GoldenRevision("gateway-application-role", digest: "1CfpIPrpl4EoRrQU9eimlM8i2ArNVdpbTk3mIAsBgXs", assembler: 1, healthKit: 1), - GoldenRevision("gateway-role", digest: "JtaVascxlW4cJfq-aH6p2JDab9u-YfQiaSFtwvhiMFY", assembler: 1, healthKit: 1), + GoldenRevision("electrocardiogram-symptom-companion", digest: "EHYE0r3jfMVT2I5fBcnIQaiHnW0oaV_mZh3V12xCWDI", assembler: 1, healthKit: 2), + GoldenRevision("electrocardiogram-with-symptom", digest: "oUCBD9zurrtjI0O-DbOxhf1Uo_QVwWYGQTt8HloMz9M", assembler: 1, healthKit: 2), + GoldenRevision("electrocardiogram", digest: "qs8pgYDPAUqNBwnZaUsd3cKARQ-tuJWip2AexfWbMgA", assembler: 1, healthKit: 2), + GoldenRevision("gateway-application-role", digest: "z4GLZX9z_-CYLMxzF6l78eLQXXDu_vCV6gHzIRVouYY", assembler: 1, healthKit: 2), + GoldenRevision("gateway-role", digest: "6cz0Bpd-k9mt_HFFY8xyRT3dkjpDMjI8WnqlyMlGgO8", assembler: 1, healthKit: 2), GoldenRevision("heart-rate-device-without-unit-token", digest: "gKIE0MA3n8uoEIiPTWI-TJOBDAD1osZVz6C0sWLibk8", assembler: 1, healthKit: 1), GoldenRevision("heart-rate-interval", digest: "D4QTr9s6IiDjDLGr6Gm41p4QjU8Go6oXajrRteRhwaU", assembler: 1, healthKit: 1), GoldenRevision("heart-rate-minimal", digest: "iYrgj5FAgmujztGZvH5fPK2gu0rzDPJF0Z3CSWallZ0", assembler: 1, healthKit: 1), @@ -60,10 +60,10 @@ struct GoldenOutputRevisionTests { GoldenRevision("heart-rate-no-time-zone", digest: "7tJhGKGIbj6MVPQ2P4cNI0KN-MLI2MBUk763HC5kkfk", assembler: 1, healthKit: 1), GoldenRevision("heart-rate-recording-device", digest: "IIHNioDM2ZkeqNYCg_8f0HPuPC3b-pPdHziLJEm2j3U", assembler: 1, healthKit: 1), GoldenRevision("heart-rate-study", digest: "sftiHrOuakPAfN5bjto9VoPE7_RpZ1k3YcGDKEqkFDI", assembler: 1, healthKit: 1), - GoldenRevision("heartbeat-series", digest: "lkN3HRrrJDbWJil2kZg3LKKgmRGyzmEVWgJEugZroEM", assembler: 1, healthKit: 1), + GoldenRevision("heartbeat-series", digest: "fB3bdqSnBH2vJxBfzQQDFFeItPoT6Bs8Yom7uFbYS98", assembler: 1, healthKit: 2), GoldenRevision("insulin-delivery-bolus", digest: "fCw3-HgNHCW_r1bQ8bY5WiGz52iekzNbJ0-AKZp59yc", assembler: 1, healthKit: 1), - GoldenRevision("native-identifier-disclosure", digest: "FUSVYtEc61Y5479e6WSJYoDPoJz4x5BRgpp61H0DP0I", assembler: 1, healthKit: 1), - GoldenRevision("outlines", digest: "dcGlAzsmhgyWChE4Tc78Y_kC0ZQmp5IJ-NKab8fLrZA", assembler: 1, healthKit: 1), + GoldenRevision("native-identifier-disclosure", digest: "d0cEPkdGfs7W8CYbUpS-GDKoc64jN21WjgkWSibIAAM", assembler: 1, healthKit: 2), + GoldenRevision("outlines", digest: "cPcJEmmsQYu93MgmKbOTjuqgyorDKhDZb54gpvyroTs", assembler: 1, healthKit: 2), GoldenRevision("repository-ids-on-every-node", digest: "wnO8sPt82cYYd4m50n4tycbEXWdgvNRlKjQItQI6n4Y", assembler: 1, healthKit: 1), GoldenRevision("retraction-blood-pressure", digest: "x4muVgyjqh8AfgVGhaS55MeMVmxJ58UR0hsghhedkEA", assembler: 1, healthKit: 1), GoldenRevision("retraction-electrocardiogram", digest: "JJIp4J2S4Vr0CX-d1fi3IqAmyNzuzSz4fyrF-gbrkgM", assembler: 1, healthKit: 1), @@ -74,15 +74,15 @@ struct GoldenOutputRevisionTests { GoldenRevision("state-of-mind", digest: "tKLQnzIzG1NWFOB2Tlfy4wcZ30_0JzFq4iPyzcLUFXc", assembler: 1, healthKit: 1), GoldenRevision("step-count-period", digest: "EGtl-T8Y_4ZYOsQrwTOwooimTqzOPzOizTeh_1xUyuI", assembler: 1, healthKit: 1), GoldenRevision("sync-identity", digest: "AVB5QYfWDT4HHvzqxJ7SMeUMLU4miCMWO0m8tjG6Vyg", assembler: 1, healthKit: 1), - GoldenRevision("two-study-enrollments", digest: "6xtFx6cUROnfra3ZXo_ItI81yhmfSSCsXe9nlJb039A", assembler: 1, healthKit: 1), - GoldenRevision("udi-disclosure", digest: "U6I4SPk8ZMG1qYnzUpuuXmtZmPJ9bwdCinbmH515Bgw", assembler: 1, healthKit: 1), - GoldenRevision("workout-route", digest: "qcXsPsBE21qllakPbqcY5JziHqKDqq_Kr5wPgr8ppks", assembler: 1, healthKit: 1), + GoldenRevision("two-study-enrollments", digest: "_LQH7q4xMKuGfcWl6_Ad65hcTU6PDJ_C_Xd31ZGD0HQ", assembler: 1, healthKit: 2), + GoldenRevision("udi-disclosure", digest: "WzH-xG6V54w8RejhkvpOo7L__Xi3J6qZc1giw8-ps4M", assembler: 1, healthKit: 2), + GoldenRevision("workout-route", digest: "PBv3pI8sKIsHZAKmYK_9eTawK56ITbaCGS2miDe0Cxc", assembler: 1, healthKit: 2), GoldenRevision("workout-session", digest: "1JlAdaXFilr2KXrYdxEvZXAGjMUaSxFaJfiPpZuvGlE", assembler: 1, healthKit: 1), GoldenRevision("writer-blank-name-with-sync-identity", digest: "eGHwwHdaM8H_QqW2kRQqNcXBj-309dPxpqy3gkXnKNU", assembler: 1, healthKit: 1), - GoldenRevision("writer-device-classification-without-recording-device", digest: "SnLRcZTmF2g6qdUj-M4UiX6yZGYMavPfLDzJ_3hQPeY", assembler: 1, healthKit: 1), - GoldenRevision("writer-device-classification", digest: "yZStG8Raudsb--4jeSQkKpkr1ZctGAOJKy81JTmYNMs", assembler: 1, healthKit: 1), GoldenRevision("writer-foreign-application", digest: "SaD46SDNVFB6NPQJmIBglAQpwczYwAKlQvSlLl8-d24", assembler: 1, healthKit: 1), GoldenRevision("writer-host-equals-converter-host", digest: "fGxbULDNVld5Ke8SXJEiEaHwi_W-3p2KTFpG7i6jQQs", assembler: 1, healthKit: 1), + GoldenRevision("writer-omitted-without-recording-device", digest: "SnLRcZTmF2g6qdUj-M4UiX6yZGYMavPfLDzJ_3hQPeY", assembler: 1, healthKit: 1), + GoldenRevision("writer-omitted", digest: "eJqZQLyxYaLExf9ESiJxNRcvk6pO9_9vyX3ZBlqU5OU", assembler: 1, healthKit: 2), GoldenRevision("writer-self-build-equals-revision", digest: "eqwa6qOx48BRIZuR-XapwsKmhNC5G_IaKGtHU_drvVc", assembler: 1, healthKit: 1), GoldenRevision("writer-self-older-build", digest: "q59J2fyLBpYqXMqk2gBm1xqXtOmgW3uCHWFMaeQgF5Q", assembler: 1, healthKit: 1), GoldenRevision("writer-self-token-identical", digest: "jAlS6dY8iVYxVegEVLk8WC2TOmLam51chxDE7WuWf5k", assembler: 1, healthKit: 1), diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitDeviceIdentityTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitDeviceIdentityTests.swift index d37c529d5..9f32c7390 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitDeviceIdentityTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitDeviceIdentityTests.swift @@ -25,7 +25,7 @@ struct HealthKitFHIRDeviceIdentityTests { subjectID: String = "1a2b3c", eventOffset: TimeInterval = 0, stableUnitToken: String? = nil, - writer: HealthKitWriter = .application + writer: HealthKitWriter = .omit ) -> HealthKitConversionContext { HealthKitConversionContext( subject: .logical(.test(.patient, subjectID)), @@ -157,18 +157,16 @@ struct HealthKitFHIRDeviceIdentityTests { #expect(conversion.graphIdentifiers.recordingDeviceSnapshot != nil) } - @Test("A device source reuses the dual-identity recording snapshot as its Provenance author") - func deviceSourceReusesRecordingDevice() throws { - let conversion = try converter.convert( - sample(watch()), - context: context(stableUnitToken: "watch-unit-7", writer: .device) - ) - let author = try #require(conversion.provenance.entity?.first?.agent?.first) + @Test("An unclassified source keeps the recording Device its HKDevice names, and the Provenance names no author") + func unclassifiedSourceKeepsTheRecordingDevice() throws { + let attributed = try StoredSampleFixtures.stored(sample(watch()), uuid: GoldenFixtures.uuid(0xB7), writer: GoldenFixtures.foreignWriter) + let conversion = try converter.convert(attributed, context: context(stableUnitToken: "watch-unit-7", writer: .omit)) + let recordingDevice = try #require(conversion.graphIdentifiers.recordingDeviceSnapshot) #expect(conversion.writer == nil) - #expect(author.who.reference == conversion.observation.device?.reference) #expect(conversion.graphIdentifiers.writerSnapshot == nil) - #expect(conversion.graphIdentifiers.recordingDeviceSnapshot != nil) + #expect(conversion.provenance.entity?.first?.agent == nil) + #expect(conversion.observation.device?.reference?.value?.string == (try recordingDevice.fullURLString)) } } diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFingerprintTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFingerprintTests.swift index 087e0ebba..fed7cc69e 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFingerprintTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFingerprintTests.swift @@ -43,9 +43,10 @@ struct HealthKitFHIRExporterFingerprintTests { return [ ("route", { $0.route = .authorized }), ("legacyBundleID", { $0.legacyBundleID = .healthKitUUID }), - ("writer application", { $0.writer = .application }), - ("writer device", { $0.writer = .device }), - ("writer omit", { $0.writer = .omit }), + ("writer applications", { $0.writer = .applications(["org.example.writer"]) }), + ("writer applications member", { $0.writer = .applications(["org.example.writer", "org.example.other"]) }), + ("writer applications empty", { $0.writer = .applications([]) }), + ("writer classify", { $0.writer = .classify { _ in .application } }), ("recordingDevice omit", { $0.recordingDevice = .omit }), ("recordingDevice custom", { $0.recordingDevice = .custom(NoRecordingDevice()) }), ("role gatewayForOwnWrites", { $0.role = .gatewayForOwnWrites }), @@ -126,6 +127,37 @@ struct HealthKitFHIRExporterFingerprintTests { #expect(changed[0].event != original[0].event, "\(contexts[1].0) reused an event") } + @Test("A writer-policy change gives a reserved record a new sequence, never one handed out under another policy") + func writerPolicyChangeTakesANewSequence() throws { + let sequencer = ExchangeEventSequencer.inMemory() + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(2), writer: GoldenFixtures.foreignWriter) + let omitting = try Fixtures.exporter(sequencer: sequencer) + let classifying = try Fixtures.exporter(sequencer: sequencer) { $0.writer = .applications([GoldenFixtures.foreignWriter.bundleIdentifier]) } + let (omitted, _) = try Fixtures.collect(omitting, samples: [sample]) + let (stated, _) = try Fixtures.collect(classifying, samples: [sample]) + let (reverted, _) = try Fixtures.collect(omitting, samples: [sample]) + #expect([omitted, stated, reverted].map { $0.first?.sequence } == ["1", "2", "3"]) + #expect(stated.first?.graph?.json != omitted.first?.graph?.json, "the classified source states its writer") + } + + @Test("Equal application sets fingerprint equally, whatever order their members were inserted in") + func applicationSetsFingerprintByMembership() throws { + let identifiers = (0..<24).map { "org.example.app\($0)" } + let inserted = Set(identifiers) + var reversed = Set(minimumCapacity: 512) + for identifier in identifiers.reversed() { + reversed.insert(identifier) + } + try #require(inserted == reversed) + try #require(Array(inserted) != Array(reversed), "the two sets must iterate in different orders for this test to discriminate") + let key = ExchangeEventKey.active(type: .heartRate, uuid: GoldenFixtures.uuid(1)) + func fingerprint(_ bundleIdentifiers: Set) throws -> String { + try Fixtures.exporter { $0.writer = .applications(bundleIdentifiers) }.context.request(for: key).fingerprint + } + #expect(try fingerprint(inserted) == fingerprint(reversed)) + #expect(try fingerprint(inserted) != fingerprint(inserted.subtracting(["org.example.app0"]))) + } + @Test("G3b: the fingerprint covers every stored option, each under its own name and with its own value") @available(*, deprecated, message: "Names the transitional legacy Bundle.id case") func fingerprintCoversEveryOption() { diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift index 0fefd28cf..2a87d4ac5 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift @@ -147,36 +147,6 @@ struct HealthKitFHIRExporterTests { #expect(try !storage.holdsReservation(for: ecgKey)) } - @Test("Under the automatic writer policy an Apple per-device source is the recording Device that authored the sample") - func automaticWriterClassifiesAppleDeviceSources() throws { - let exporter = try Self.exporter() - let watchSource = StoredSampleFixtures.Writer( - name: "Lukas's Apple Watch", - bundleIdentifier: "com.apple.health.6C4B1D1E-0000-4000-8000-000000000009", - version: "26.1", - productType: "Watch7,12" - ) - let fromWatch = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(7), writer: watchSource) - let fromApp = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(8), writer: GoldenFixtures.foreignWriter) - let (exports, _) = try Self.collect(exporter, [fromWatch, fromApp]) - let watchBundle = try #require(exports[0].graph?.bundle) - let devices = watchBundle.entry?.compactMap { $0.resource?.get(if: Device.self) } ?? [] - let recorder = try #require(devices.first { $0.manufacturer?.value?.string == "Apple Inc." }) - #expect(recorder.deviceName?.first?.name.value?.string == "Lukas's Apple Watch") - #expect(recorder.modelNumber?.value?.string == "Watch7,12") - #expect(recorder.meta?.profile?.contains(Profile.groveRecordingDevice) == true) - let provenance = try #require(watchBundle.entry?.compactMap { $0.resource?.get(if: Provenance.self) }.first) - let recorderURL = try #require(watchBundle.entry?.first { $0.resource?.get(if: Device.self) == recorder }?.fullUrl?.value?.url.absoluteString) - let author = provenance.entity?.first?.agent?.first { agent in - agent.type?.coding?.contains { $0.code?.value?.string == "author" } == true - } - #expect(author?.who.reference?.value?.string == recorderURL) - #expect(exports[0].warnings.isEmpty) - // The application source converts exactly as the old entry point's default (`.application`) did. - let reference = try Self.reference(fromApp, event: exports[1].event, instant: GoldenFixtures.conversionInstant) - #expect(exports[1].graph?.json == reference.graph.json) - } - @Test("The omit policies state nothing and never warn; the legacy Bundle.id keeps the HealthKit UUID") func policiesApply() throws { let exporter = try Self.exporter { options in diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterWriterTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterWriterTests.swift new file mode 100644 index 000000000..29b04f661 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterWriterTests.swift @@ -0,0 +1,242 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit +import ModelsR4 +import Testing + + +/// The bundle identifiers of the sources a classifying closure was asked about. +private final class AskedSources: @unchecked Sendable { // `asked` is guarded by `lock`. + private let lock = NSLock() + private var asked: [String] = [] + + var bundleIdentifiers: [String] { + lock.lock() + defer { + lock.unlock() + } + return asked + } + + func record(_ source: HKSource) { + lock.lock() + defer { + lock.unlock() + } + asked.append(source.bundleIdentifier) + } +} + + +/// W1 to W4: only the caller's classification states a writer. `HKSourceRevision` does not say whether a source +/// is an application or a device, and the HealthKit guide forbids classifying it from the bundle identifier's +/// shape, the source name or the product type (`mapping.md`, writer rules); the recording Device stays whatever +/// the recording-device policy resolves from `HKDevice`. +@Suite +struct HealthKitFHIRExporterWriterTests { + private typealias Fixtures = ExporterFixtures + + /// An Apple per-device source: the watch that recorded the sample itself, as HealthKit names it. + private static let watchSource = StoredSampleFixtures.Writer( + name: "Lukas's Apple Watch", + bundleIdentifier: "com.apple.health.6C4B1D1E-0000-4000-8000-000000000009", + version: "26.1", + productType: "Watch7,12" + ) + + /// An application the callers below never classify. + private static let otherApplication = StoredSampleFixtures.Writer( + name: "Other Writer", + bundleIdentifier: "org.example.other", + version: "7", + productType: "iPhone17,1" + ) + + /// The converting application's bundle identifier: the only one a graph without a writer states. + private static let converterBundleIdentifier = ExporterFixtures.base.application.bundleIdentifier + + private static func devices(_ bundle: ModelsR4.Bundle) -> [(url: String?, device: Device)] { + (bundle.entry ?? []).compactMap { entry in + entry.resource?.get(if: Device.self).map { (entry.fullUrl?.value?.url.absoluteString, $0) } + } + } + + /// Every clear Apple bundle identifier the graph's Devices state. + private static func statedBundleIdentifiers(_ bundle: ModelsR4.Bundle) -> Set { + Set(devices(bundle).flatMap { _, device in + (device.identifier ?? []) + .filter { $0.system == HealthKitContract.appleBundleIdentifierSystem } + .compactMap { $0.value?.value?.string } + }) + } + + /// The Device stating `bundleIdentifier`, with its fullUrl. + private static func device(stating bundleIdentifier: String, in bundle: ModelsR4.Bundle) -> (url: String?, device: Device)? { + devices(bundle).first { _, device in + device.identifier?.contains { $0.value?.value?.string == bundleIdentifier } == true + } + } + + private static func recordingDevices(_ bundle: ModelsR4.Bundle) -> [Device] { + devices(bundle).map(\.device).filter { $0.meta?.profile?.contains(Profile.groveRecordingDevice) == true } + } + + /// The reference of the Provenance agent typed `author`, if any. + private static func author(_ bundle: ModelsR4.Bundle) -> String? { + let provenance = bundle.entry?.compactMap { $0.resource?.get(if: Provenance.self) }.first + let author = provenance?.entity?.first?.agent?.first { agent in + agent.type?.coding?.contains { $0.code?.value?.string == "author" } == true + } + return author?.who.reference?.value?.string + } + + /// Whether the graph states the application writer `writer`, exactly as the sample's `HKSourceRevision` names it. + private static func statesWriter(_ writer: StoredSampleFixtures.Writer, in bundle: ModelsR4.Bundle) throws -> Bool { + let stated = try #require(device(stating: writer.bundleIdentifier, in: bundle)) + #expect(stated.device.deviceName?.first?.name.value?.string == writer.name) + #expect(stated.device.version?.contains { $0.value.value?.string == writer.version } == true) + #expect(author(bundle) == stated.url, "the writer is the Provenance author") + return true + } + + /// Asserts that the graph states no writer and no author, and no Device names the source. + private static func statesNoWriter(_ bundle: ModelsR4.Bundle, source: StoredSampleFixtures.Writer) { + #expect(statedBundleIdentifiers(bundle) == [converterBundleIdentifier], "\(source.bundleIdentifier) is stated") + #expect(author(bundle) == nil, "the Provenance names an author for \(source.bundleIdentifier)") + #expect(devices(bundle).allSatisfy { $0.device.deviceName?.first?.name.value?.string != source.name }) + } + + private static func exports( + _ exporter: HealthKitFHIRExporter, + _ samples: [HKSample] + ) throws -> [UUID: HealthKitFHIRExporter.Export] { + let (exports, _) = try Fixtures.collect(exporter, samples: samples) + return Dictionary(uniqueKeysWithValues: exports.map { ($0.source.uuid, $0) }) + } + + /// A heart rate from the Apple per-device source, converted under the conversion options' defaults. + private static func defaultConversion(_ ordinal: UInt8, device: HKDevice?) throws -> HealthKitConversion { + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(ordinal), device: device, writer: watchSource) + let context = HealthKitConversionContext(event: try GoldenFixtures.context(sequence: 300).event) + return try HealthKitConverter.convertSample(sample, context: context).primary + } + + @Test("W1: by default an Apple per-device source states no writer, no author and no recording Device of its own") + func exporterDefaultStatesNoWriter() throws { + let exporter = try Fixtures.exporter() + guard case .omit = exporter.options.writer else { + Issue.record("the default writer policy is \(exporter.options.writer), not omit") + return + } + let bare = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0x31), writer: Self.watchSource) + let declined = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0x32), device: GoldenFixtures.watchWithoutUnitToken, writer: Self.watchSource) + let resolved = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0x33), device: GoldenFixtures.watch, writer: Self.watchSource) + let exports = try Self.exports(exporter, [bare, declined, resolved]) + let bundles = try [bare, declined, resolved].map { try #require(exports[$0.uuid]?.graph?.bundle) } + for bundle in bundles { + Self.statesNoWriter(bundle, source: Self.watchSource) + } + // No `HKDevice`: no recording Device and nothing to report. + #expect(Self.recordingDevices(bundles[0]).isEmpty) + #expect(exports[bare.uuid]?.warnings.isEmpty == true) + // An `HKDevice` the policy declined: no recording Device, and the omission is reported. + #expect(Self.recordingDevices(bundles[1]).isEmpty) + #expect(exports[declined.uuid]?.warnings == [ExchangeGraphRule.mobileOmissionRecordingDevice.diagnostic]) + // An `HKDevice` the policy resolved: its recording Device, named by the `HKDevice`, and no warning. + #expect(Self.recordingDevices(bundles[2]).map { $0.deviceName?.first?.name.value?.string } == ["Apple Watch"]) + #expect(exports[resolved.uuid]?.warnings.isEmpty == true) + } + + @Test("W1: the conversion options default to no writer too, with the same recording Device and warning") + func conversionOptionsDefaultStatesNoWriter() throws { + #expect(HealthKitConversionOptions().writer == .omit) + #expect(HealthKitConversionOptions.default.writer == .omit) + let bare = try Self.defaultConversion(0x34, device: nil) + let declined = try Self.defaultConversion(0x35, device: GoldenFixtures.watchWithoutUnitToken) + let resolved = try Self.defaultConversion(0x36, device: GoldenFixtures.watch) + for conversion in [bare, declined, resolved] { + Self.statesNoWriter(conversion.graph.bundle, source: Self.watchSource) + #expect(conversion.writer == nil) + } + #expect(bare.recordingDevice == nil) + #expect(bare.warnings.isEmpty) + #expect(declined.recordingDevice == nil) + #expect(declined.warnings == [.recordingDeviceOmitted(deviceName: "Apple Watch")]) + #expect(resolved.recordingDevice?.deviceName?.first?.name.value?.string == "Apple Watch") + #expect(resolved.warnings.isEmpty) + } + + @Test("W2: a listed bundle identifier states its application writer from the sample's own source revision; others state none") + func listedApplicationsStateTheirWriter() throws { + let exporter = try Fixtures.exporter { $0.writer = .applications([GoldenFixtures.foreignWriter.bundleIdentifier]) } + let listed = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0x41), device: GoldenFixtures.watch, writer: GoldenFixtures.foreignWriter) + let unlisted = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0x42), device: GoldenFixtures.watch, writer: Self.otherApplication) + let watch = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0x43), device: GoldenFixtures.watch, writer: Self.watchSource) + let exports = try Self.exports(exporter, [listed, unlisted, watch]) + let listedExport = try #require(exports[listed.uuid]) + #expect(try Self.statesWriter(GoldenFixtures.foreignWriter, in: try #require(listedExport.graph?.bundle))) + Self.statesNoWriter(try #require(exports[unlisted.uuid]?.graph?.bundle), source: Self.otherApplication) + Self.statesNoWriter(try #require(exports[watch.uuid]?.graph?.bundle), source: Self.watchSource) + // The listed source converts exactly as the entry point does with the source classified as an application. + let base = Fixtures.base + let context = HealthKitConversionContext( + event: try ExchangeEventContext( + subject: base.subject, + event: try #require(listedExport.event), + identityScope: base.identityScope, + repositoryScope: base.repositoryScope, + application: base.application, + host: base.host, + conversionInstant: GoldenFixtures.conversionInstant + ), + options: HealthKitConversionOptions(writer: .application) + ) + let reference = try HealthKitConverter.convertSample(listed, context: context).primary + #expect(listedExport.graph?.json == reference.graph.json) + } + + @Test("W3: a classifying closure is asked per source; an application states the revision's values, an omission nothing") + func classifyingClosureDecidesPerSource() throws { + let asked = AskedSources() + let exporter = try Fixtures.exporter { options in + options.writer = .classify { source in + asked.record(source) + return source.bundleIdentifier == GoldenFixtures.foreignWriter.bundleIdentifier ? .application : .omit + } + } + let classified = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0x51), writer: GoldenFixtures.foreignWriter) + let omitted = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0x52), writer: Self.otherApplication) + let exports = try Self.exports(exporter, [classified, omitted]) + #expect(asked.bundleIdentifiers.sorted() == [Self.otherApplication.bundleIdentifier, GoldenFixtures.foreignWriter.bundleIdentifier].sorted()) + #expect(try Self.statesWriter(GoldenFixtures.foreignWriter, in: try #require(exports[classified.uuid]?.graph?.bundle))) + Self.statesNoWriter(try #require(exports[omitted.uuid]?.graph?.bundle), source: Self.otherApplication) + } + + @Test("W4: no source file of the adapter names Apple's per-device bundle-identifier prefix") + func noSourceNamesThePerDevicePrefix() throws { + let sources = URL(fileURLWithPath: #filePath) + .deletingLastPathComponent() + .deletingLastPathComponent() + .deletingLastPathComponent() + .appendingPathComponent("Sources/GroveHealthKitFHIR", isDirectory: true) + let files = try FileManager.default.subpathsOfDirectory(atPath: sources.path).filter { $0.hasSuffix(".swift") } + try #require(!files.isEmpty, "no adapter sources at \(sources.path)") + for file in files { + let text = try String(contentsOf: sources.appendingPathComponent(file), encoding: .utf8) + #expect(!text.contains("\"com.apple.health."), "\(file) names the Apple per-device source prefix") + } + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRTestContext.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRTestContext.swift index 3ddef0be3..4a57cf887 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRTestContext.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRTestContext.swift @@ -156,7 +156,7 @@ extension HealthKitConversionContext { converter: ApplicationDevice = .test, converterHost: HostDevice = .test, graphIdentifierSystem: IdentifierSystem? = nil, - writer: HealthKitWriter = .application, + writer: HealthKitWriter = .omit, converterWasGateway: Bool = false, conversionInstant: Date = ExchangeEventContext.testInstant, recordingDeviceStableUnitToken: String? = nil, diff --git a/Tests/GroveHealthKitFHIRTests/ProducerAlignmentTests.swift b/Tests/GroveHealthKitFHIRTests/ProducerAlignmentTests.swift index 5d46701de..f0d69e3c5 100644 --- a/Tests/GroveHealthKitFHIRTests/ProducerAlignmentTests.swift +++ b/Tests/GroveHealthKitFHIRTests/ProducerAlignmentTests.swift @@ -76,7 +76,7 @@ struct ProducerDefaultsTests { @Test("Every HealthKit disclosure omits and the recording device resolves by local identifier") func healthKitOptionDefaults() { for options in [HealthKitConversionOptions(), .default, HealthKitConversionContext(event: .test()).options] { - #expect(options.writer == .application) + #expect(options.writer == .omit) #expect(options.recordingDevice is HealthKitLocalIdentifierResolver) #expect(options.udiDisclosure == .omit) #expect(options.routeDisclosure == .omit) @@ -298,7 +298,7 @@ struct ProducerSurfaceTests { try HealthKitConverter().convert(Self.heartRate, context: context) } } - let conversion = try HealthKitConverter().convert(Self.heartRate, context: HealthKitConversionContext(writer: .device)) + let conversion = try HealthKitConverter().convert(Self.heartRate, context: HealthKitConversionContext(writer: .omit)) #expect(conversion.graphIdentifiers.writerSnapshot == nil) #expect(conversion.graphIdentifiers.writerHostSnapshot == nil) } diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/bundled-patient-subject.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/bundled-patient-subject.json index 2ad984f15..a927f017a 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/bundled-patient-subject.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/bundled-patient-subject.json @@ -377,142 +377,6 @@ ] } }, - { - "extension" : [ - { - "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", - "valueIdentifier" : { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:7zKG772wpnhNjRFdQUlSF2bgzCLS0psSYI8jDlCBDmI" - } - } - ], - "fullUrl" : "urn:uuid:27bc90ae-3192-5159-990d-4764c5569192", - "resource" : { - "identifier" : [ - { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:7zKG772wpnhNjRFdQUlSF2bgzCLS0psSYI8jDlCBDmI" - } - ], - "meta" : { - "profile" : [ - "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" - ] - }, - "modelNumber" : "iPhone17,1", - "resourceType" : "Device", - "status" : "active", - "version" : [ - { - "type" : { - "coding" : [ - { - "code" : "os-version", - "display" : "Operating system version", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" - } - ] - }, - "value" : "26.1.0" - } - ] - } - }, - { - "extension" : [ - { - "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", - "valueIdentifier" : { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:NEec450y0sraR7xbqWgH3yVUfbenpZd3_EXE6szNmrM" - } - } - ], - "fullUrl" : "urn:uuid:dafff25f-7b2a-50f1-8062-35eaaa6d3c23", - "resource" : { - "deviceName" : [ - { - "name" : "Example Writer", - "type" : "user-friendly-name" - } - ], - "identifier" : [ - { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:NEec450y0sraR7xbqWgH3yVUfbenpZd3_EXE6szNmrM" - }, - { - "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", - "type" : { - "coding" : [ - { - "code" : "apple-bundle-id", - "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" - } - ] - }, - "value" : "org.example.writer" - } - ], - "meta" : { - "profile" : [ - "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" - ] - }, - "parent" : { - "reference" : "urn:uuid:27bc90ae-3192-5159-990d-4764c5569192" - }, - "resourceType" : "Device", - "status" : "active", - "version" : [ - { - "type" : { - "coding" : [ - { - "code" : "531975", - "display" : "MDC_ID_PROD_SPEC_SW", - "system" : "urn:iso:std:iso:11073:10101" - } - ] - }, - "value" : "42" - } - ] - } - }, { "extension" : [ { @@ -560,22 +424,6 @@ ], "entity" : [ { - "agent" : [ - { - "type" : { - "coding" : [ - { - "code" : "author", - "display" : "Author", - "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" - } - ] - }, - "who" : { - "reference" : "urn:uuid:dafff25f-7b2a-50f1-8062-35eaaa6d3c23" - } - } - ], "role" : "source", "what" : { "identifier" : { diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram-symptom-companion.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram-symptom-companion.json index ed704f083..36735ad4b 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram-symptom-companion.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram-symptom-companion.json @@ -358,142 +358,6 @@ ] } }, - { - "extension" : [ - { - "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", - "valueIdentifier" : { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:ev4pSJxtJxgCn6I6NDCdnbGMIjNZ8UeRnKZ37mpcoiI" - } - } - ], - "fullUrl" : "urn:uuid:342152e5-0fa1-578f-ae92-0d3bc245ea35", - "resource" : { - "identifier" : [ - { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:ev4pSJxtJxgCn6I6NDCdnbGMIjNZ8UeRnKZ37mpcoiI" - } - ], - "meta" : { - "profile" : [ - "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" - ] - }, - "modelNumber" : "iPhone17,1", - "resourceType" : "Device", - "status" : "active", - "version" : [ - { - "type" : { - "coding" : [ - { - "code" : "os-version", - "display" : "Operating system version", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" - } - ] - }, - "value" : "26.1.0" - } - ] - } - }, - { - "extension" : [ - { - "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", - "valueIdentifier" : { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:SsFGcQUFXzymFU5DlqvKSv5JIcmRgG5ElFKAzjodj_8" - } - } - ], - "fullUrl" : "urn:uuid:7cdf03d0-e248-5b92-901d-299e17845605", - "resource" : { - "deviceName" : [ - { - "name" : "Example Writer", - "type" : "user-friendly-name" - } - ], - "identifier" : [ - { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:SsFGcQUFXzymFU5DlqvKSv5JIcmRgG5ElFKAzjodj_8" - }, - { - "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", - "type" : { - "coding" : [ - { - "code" : "apple-bundle-id", - "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" - } - ] - }, - "value" : "org.example.writer" - } - ], - "meta" : { - "profile" : [ - "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" - ] - }, - "parent" : { - "reference" : "urn:uuid:342152e5-0fa1-578f-ae92-0d3bc245ea35" - }, - "resourceType" : "Device", - "status" : "active", - "version" : [ - { - "type" : { - "coding" : [ - { - "code" : "531975", - "display" : "MDC_ID_PROD_SPEC_SW", - "system" : "urn:iso:std:iso:11073:10101" - } - ] - }, - "value" : "42" - } - ] - } - }, { "extension" : [ { @@ -541,22 +405,6 @@ ], "entity" : [ { - "agent" : [ - { - "type" : { - "coding" : [ - { - "code" : "author", - "display" : "Author", - "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" - } - ] - }, - "who" : { - "reference" : "urn:uuid:7cdf03d0-e248-5b92-901d-299e17845605" - } - } - ], "role" : "source", "what" : { "identifier" : { diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram-with-symptom.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram-with-symptom.json index fae0b2d9a..2ffe6a8f0 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram-with-symptom.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram-with-symptom.json @@ -506,142 +506,6 @@ ] } }, - { - "extension" : [ - { - "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", - "valueIdentifier" : { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:s8buBEyG4yRzKd2hA02jUKfwT2IN5N5psYD2moM7mb4" - } - } - ], - "fullUrl" : "urn:uuid:08844702-36cb-57ff-b249-2b1b843fb79f", - "resource" : { - "identifier" : [ - { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:s8buBEyG4yRzKd2hA02jUKfwT2IN5N5psYD2moM7mb4" - } - ], - "meta" : { - "profile" : [ - "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" - ] - }, - "modelNumber" : "iPhone17,1", - "resourceType" : "Device", - "status" : "active", - "version" : [ - { - "type" : { - "coding" : [ - { - "code" : "os-version", - "display" : "Operating system version", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" - } - ] - }, - "value" : "26.1.0" - } - ] - } - }, - { - "extension" : [ - { - "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", - "valueIdentifier" : { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:7oVlArgLSpX9m-sICbkampE5_6rdy4EpAz-xyYWON1o" - } - } - ], - "fullUrl" : "urn:uuid:965a804c-2f33-5fe0-ae1e-a4a328007269", - "resource" : { - "deviceName" : [ - { - "name" : "Example Writer", - "type" : "user-friendly-name" - } - ], - "identifier" : [ - { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:7oVlArgLSpX9m-sICbkampE5_6rdy4EpAz-xyYWON1o" - }, - { - "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", - "type" : { - "coding" : [ - { - "code" : "apple-bundle-id", - "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" - } - ] - }, - "value" : "org.example.writer" - } - ], - "meta" : { - "profile" : [ - "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" - ] - }, - "parent" : { - "reference" : "urn:uuid:08844702-36cb-57ff-b249-2b1b843fb79f" - }, - "resourceType" : "Device", - "status" : "active", - "version" : [ - { - "type" : { - "coding" : [ - { - "code" : "531975", - "display" : "MDC_ID_PROD_SPEC_SW", - "system" : "urn:iso:std:iso:11073:10101" - } - ] - }, - "value" : "42" - } - ] - } - }, { "extension" : [ { @@ -689,22 +553,6 @@ ], "entity" : [ { - "agent" : [ - { - "type" : { - "coding" : [ - { - "code" : "author", - "display" : "Author", - "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" - } - ] - }, - "who" : { - "reference" : "urn:uuid:965a804c-2f33-5fe0-ae1e-a4a328007269" - } - } - ], "role" : "source", "what" : { "identifier" : { diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram.json index a73617a4b..41b4792ff 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/electrocardiogram.json @@ -489,142 +489,6 @@ ] } }, - { - "extension" : [ - { - "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", - "valueIdentifier" : { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:CqlhnFqMlGAci4vaQkCBgBeUJF9aA3J1bjjEXCs6pNE" - } - } - ], - "fullUrl" : "urn:uuid:659ba41a-b773-5177-9923-8a596c45de30", - "resource" : { - "identifier" : [ - { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:CqlhnFqMlGAci4vaQkCBgBeUJF9aA3J1bjjEXCs6pNE" - } - ], - "meta" : { - "profile" : [ - "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" - ] - }, - "modelNumber" : "iPhone17,1", - "resourceType" : "Device", - "status" : "active", - "version" : [ - { - "type" : { - "coding" : [ - { - "code" : "os-version", - "display" : "Operating system version", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" - } - ] - }, - "value" : "26.1.0" - } - ] - } - }, - { - "extension" : [ - { - "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", - "valueIdentifier" : { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:ZhPvEZjeAyTc7gzk7uluiB_0SIAc29eOtaofueV0kCs" - } - } - ], - "fullUrl" : "urn:uuid:ac9e967e-1606-58e5-8a33-72e6f7e602af", - "resource" : { - "deviceName" : [ - { - "name" : "Example Writer", - "type" : "user-friendly-name" - } - ], - "identifier" : [ - { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:ZhPvEZjeAyTc7gzk7uluiB_0SIAc29eOtaofueV0kCs" - }, - { - "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", - "type" : { - "coding" : [ - { - "code" : "apple-bundle-id", - "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" - } - ] - }, - "value" : "org.example.writer" - } - ], - "meta" : { - "profile" : [ - "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" - ] - }, - "parent" : { - "reference" : "urn:uuid:659ba41a-b773-5177-9923-8a596c45de30" - }, - "resourceType" : "Device", - "status" : "active", - "version" : [ - { - "type" : { - "coding" : [ - { - "code" : "531975", - "display" : "MDC_ID_PROD_SPEC_SW", - "system" : "urn:iso:std:iso:11073:10101" - } - ] - }, - "value" : "42" - } - ] - } - }, { "extension" : [ { @@ -672,22 +536,6 @@ ], "entity" : [ { - "agent" : [ - { - "type" : { - "coding" : [ - { - "code" : "author", - "display" : "Author", - "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" - } - ] - }, - "who" : { - "reference" : "urn:uuid:ac9e967e-1606-58e5-8a33-72e6f7e602af" - } - } - ], "role" : "source", "what" : { "identifier" : { diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/gateway-application-role.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/gateway-application-role.json index 88f27e89d..2b5deb574 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/gateway-application-role.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/gateway-application-role.json @@ -432,142 +432,6 @@ ] } }, - { - "extension" : [ - { - "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", - "valueIdentifier" : { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:08kGbsvdtUqZumirucowZS9ePH45abfoM5O4nNX7rkk" - } - } - ], - "fullUrl" : "urn:uuid:48aeeb20-6643-5b41-b3a3-44093a548f15", - "resource" : { - "identifier" : [ - { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:08kGbsvdtUqZumirucowZS9ePH45abfoM5O4nNX7rkk" - } - ], - "meta" : { - "profile" : [ - "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" - ] - }, - "modelNumber" : "iPhone17,1", - "resourceType" : "Device", - "status" : "active", - "version" : [ - { - "type" : { - "coding" : [ - { - "code" : "os-version", - "display" : "Operating system version", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" - } - ] - }, - "value" : "26.1.0" - } - ] - } - }, - { - "extension" : [ - { - "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", - "valueIdentifier" : { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:J9lvvDAXkS_dbdj52mxPi9OlB8TwcLXwadZ2GWu6m4Q" - } - } - ], - "fullUrl" : "urn:uuid:480efa67-eb12-5f15-92ba-fbc30cf24d40", - "resource" : { - "deviceName" : [ - { - "name" : "Example Writer", - "type" : "user-friendly-name" - } - ], - "identifier" : [ - { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:J9lvvDAXkS_dbdj52mxPi9OlB8TwcLXwadZ2GWu6m4Q" - }, - { - "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", - "type" : { - "coding" : [ - { - "code" : "apple-bundle-id", - "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" - } - ] - }, - "value" : "org.example.writer" - } - ], - "meta" : { - "profile" : [ - "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" - ] - }, - "parent" : { - "reference" : "urn:uuid:48aeeb20-6643-5b41-b3a3-44093a548f15" - }, - "resourceType" : "Device", - "status" : "active", - "version" : [ - { - "type" : { - "coding" : [ - { - "code" : "531975", - "display" : "MDC_ID_PROD_SPEC_SW", - "system" : "urn:iso:std:iso:11073:10101" - } - ] - }, - "value" : "42" - } - ] - } - }, { "extension" : [ { @@ -615,22 +479,6 @@ ], "entity" : [ { - "agent" : [ - { - "type" : { - "coding" : [ - { - "code" : "author", - "display" : "Author", - "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" - } - ] - }, - "who" : { - "reference" : "urn:uuid:480efa67-eb12-5f15-92ba-fbc30cf24d40" - } - } - ], "role" : "source", "what" : { "identifier" : { diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/gateway-role.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/gateway-role.json index 3367ec691..69f11b9ad 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/gateway-role.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/gateway-role.json @@ -357,142 +357,6 @@ ] } }, - { - "extension" : [ - { - "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", - "valueIdentifier" : { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:gL3lSNl7EYteXp70F6laHYwj023D9L4lpXWNgHKH-ds" - } - } - ], - "fullUrl" : "urn:uuid:1f896505-6996-55e4-8231-8412a4c864a8", - "resource" : { - "identifier" : [ - { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:gL3lSNl7EYteXp70F6laHYwj023D9L4lpXWNgHKH-ds" - } - ], - "meta" : { - "profile" : [ - "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" - ] - }, - "modelNumber" : "iPhone17,1", - "resourceType" : "Device", - "status" : "active", - "version" : [ - { - "type" : { - "coding" : [ - { - "code" : "os-version", - "display" : "Operating system version", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" - } - ] - }, - "value" : "26.1.0" - } - ] - } - }, - { - "extension" : [ - { - "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", - "valueIdentifier" : { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:qYBO4DwuNe0zTKt3vV2rd6GhfJZ_a6meCVdUGWQ8Aqo" - } - } - ], - "fullUrl" : "urn:uuid:1fb8e303-b58a-5107-ac2d-9ddced20bb00", - "resource" : { - "deviceName" : [ - { - "name" : "Example Writer", - "type" : "user-friendly-name" - } - ], - "identifier" : [ - { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:qYBO4DwuNe0zTKt3vV2rd6GhfJZ_a6meCVdUGWQ8Aqo" - }, - { - "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", - "type" : { - "coding" : [ - { - "code" : "apple-bundle-id", - "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" - } - ] - }, - "value" : "org.example.writer" - } - ], - "meta" : { - "profile" : [ - "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" - ] - }, - "parent" : { - "reference" : "urn:uuid:1f896505-6996-55e4-8231-8412a4c864a8" - }, - "resourceType" : "Device", - "status" : "active", - "version" : [ - { - "type" : { - "coding" : [ - { - "code" : "531975", - "display" : "MDC_ID_PROD_SPEC_SW", - "system" : "urn:iso:std:iso:11073:10101" - } - ] - }, - "value" : "42" - } - ] - } - }, { "extension" : [ { @@ -540,22 +404,6 @@ ], "entity" : [ { - "agent" : [ - { - "type" : { - "coding" : [ - { - "code" : "author", - "display" : "Author", - "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" - } - ] - }, - "who" : { - "reference" : "urn:uuid:1fb8e303-b58a-5107-ac2d-9ddced20bb00" - } - } - ], "role" : "source", "what" : { "identifier" : { diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heartbeat-series.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heartbeat-series.json index 40f79a7b1..256b76208 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heartbeat-series.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/heartbeat-series.json @@ -357,142 +357,6 @@ ] } }, - { - "extension" : [ - { - "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", - "valueIdentifier" : { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:Gm4hRTUp_vyKqlJoLR1QaMBMYnADSoLLNT26d8KscYA" - } - } - ], - "fullUrl" : "urn:uuid:35f19e6b-6e60-5b6c-b203-d4ac0dce18aa", - "resource" : { - "identifier" : [ - { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:Gm4hRTUp_vyKqlJoLR1QaMBMYnADSoLLNT26d8KscYA" - } - ], - "meta" : { - "profile" : [ - "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" - ] - }, - "modelNumber" : "iPhone17,1", - "resourceType" : "Device", - "status" : "active", - "version" : [ - { - "type" : { - "coding" : [ - { - "code" : "os-version", - "display" : "Operating system version", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" - } - ] - }, - "value" : "26.1.0" - } - ] - } - }, - { - "extension" : [ - { - "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", - "valueIdentifier" : { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:fKbOYBSJFXz6oCcdT3U15J88O4mc-9SuexoDJ5mI6Wc" - } - } - ], - "fullUrl" : "urn:uuid:f72582bb-3a7c-5255-808c-cdba39fd1a84", - "resource" : { - "deviceName" : [ - { - "name" : "Example Writer", - "type" : "user-friendly-name" - } - ], - "identifier" : [ - { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:fKbOYBSJFXz6oCcdT3U15J88O4mc-9SuexoDJ5mI6Wc" - }, - { - "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", - "type" : { - "coding" : [ - { - "code" : "apple-bundle-id", - "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" - } - ] - }, - "value" : "org.example.writer" - } - ], - "meta" : { - "profile" : [ - "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" - ] - }, - "parent" : { - "reference" : "urn:uuid:35f19e6b-6e60-5b6c-b203-d4ac0dce18aa" - }, - "resourceType" : "Device", - "status" : "active", - "version" : [ - { - "type" : { - "coding" : [ - { - "code" : "531975", - "display" : "MDC_ID_PROD_SPEC_SW", - "system" : "urn:iso:std:iso:11073:10101" - } - ] - }, - "value" : "42" - } - ] - } - }, { "extension" : [ { @@ -540,22 +404,6 @@ ], "entity" : [ { - "agent" : [ - { - "type" : { - "coding" : [ - { - "code" : "author", - "display" : "Author", - "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" - } - ] - }, - "who" : { - "reference" : "urn:uuid:f72582bb-3a7c-5255-808c-cdba39fd1a84" - } - } - ], "role" : "source", "what" : { "identifier" : { diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/native-identifier-disclosure.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/native-identifier-disclosure.json index a3ada1141..b327f632d 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/native-identifier-disclosure.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/native-identifier-disclosure.json @@ -355,142 +355,6 @@ ] } }, - { - "extension" : [ - { - "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", - "valueIdentifier" : { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:6_cJPfzFz0pYAYN9M-RGyPz5Gcabdpjvh7xr3Q2anfM" - } - } - ], - "fullUrl" : "urn:uuid:51571f65-d367-5848-9557-f958f42357bc", - "resource" : { - "identifier" : [ - { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:6_cJPfzFz0pYAYN9M-RGyPz5Gcabdpjvh7xr3Q2anfM" - } - ], - "meta" : { - "profile" : [ - "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" - ] - }, - "modelNumber" : "iPhone17,1", - "resourceType" : "Device", - "status" : "active", - "version" : [ - { - "type" : { - "coding" : [ - { - "code" : "os-version", - "display" : "Operating system version", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" - } - ] - }, - "value" : "26.1.0" - } - ] - } - }, - { - "extension" : [ - { - "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", - "valueIdentifier" : { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:c8W0vHmQMLvMGY5CqBiah9DLz-rT454GqeZqtuLJrbU" - } - } - ], - "fullUrl" : "urn:uuid:647ca0a1-1154-58d5-bb7c-a880387bbbcb", - "resource" : { - "deviceName" : [ - { - "name" : "Example Writer", - "type" : "user-friendly-name" - } - ], - "identifier" : [ - { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:c8W0vHmQMLvMGY5CqBiah9DLz-rT454GqeZqtuLJrbU" - }, - { - "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", - "type" : { - "coding" : [ - { - "code" : "apple-bundle-id", - "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" - } - ] - }, - "value" : "org.example.writer" - } - ], - "meta" : { - "profile" : [ - "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" - ] - }, - "parent" : { - "reference" : "urn:uuid:51571f65-d367-5848-9557-f958f42357bc" - }, - "resourceType" : "Device", - "status" : "active", - "version" : [ - { - "type" : { - "coding" : [ - { - "code" : "531975", - "display" : "MDC_ID_PROD_SPEC_SW", - "system" : "urn:iso:std:iso:11073:10101" - } - ] - }, - "value" : "42" - } - ] - } - }, { "extension" : [ { @@ -538,22 +402,6 @@ ], "entity" : [ { - "agent" : [ - { - "type" : { - "coding" : [ - { - "code" : "author", - "display" : "Author", - "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" - } - ] - }, - "who" : { - "reference" : "urn:uuid:647ca0a1-1154-58d5-bb7c-a880387bbbcb" - } - } - ], "role" : "source", "what" : { "identifier" : { diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json index a25717341..b974ba22a 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json @@ -167,27 +167,6 @@ { "extensions" : [ - ], - "fullUrl" : "urn:uuid:27bc90ae-3192-5159-990d-4764c5569192", - "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:7zKG772wpnhNjRFdQUlSF2bgzCLS0psSYI8jDlCBDmI" - ], - "resourceType" : "Device" - }, - { - "extensions" : [ - - ], - "fullUrl" : "urn:uuid:dafff25f-7b2a-50f1-8062-35eaaa6d3c23", - "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:NEec450y0sraR7xbqWgH3yVUfbenpZd3_EXE6szNmrM", - "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" - ], - "resourceType" : "Device" - }, - { - "extensions" : [ - ], "fullUrl" : "urn:uuid:be2a33d7-8e5f-5fa9-9a3d-b5a0ee9a747c", "identifiers" : [ @@ -311,27 +290,6 @@ { "extensions" : [ - ], - "fullUrl" : "urn:uuid:659ba41a-b773-5177-9923-8a596c45de30", - "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:CqlhnFqMlGAci4vaQkCBgBeUJF9aA3J1bjjEXCs6pNE" - ], - "resourceType" : "Device" - }, - { - "extensions" : [ - - ], - "fullUrl" : "urn:uuid:ac9e967e-1606-58e5-8a33-72e6f7e602af", - "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:ZhPvEZjeAyTc7gzk7uluiB_0SIAc29eOtaofueV0kCs", - "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" - ], - "resourceType" : "Device" - }, - { - "extensions" : [ - ], "fullUrl" : "urn:uuid:68e0a782-d8a1-5e27-aaa9-b0c272c89904", "identifiers" : [ @@ -392,27 +350,6 @@ { "extensions" : [ - ], - "fullUrl" : "urn:uuid:342152e5-0fa1-578f-ae92-0d3bc245ea35", - "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:ev4pSJxtJxgCn6I6NDCdnbGMIjNZ8UeRnKZ37mpcoiI" - ], - "resourceType" : "Device" - }, - { - "extensions" : [ - - ], - "fullUrl" : "urn:uuid:7cdf03d0-e248-5b92-901d-299e17845605", - "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:SsFGcQUFXzymFU5DlqvKSv5JIcmRgG5ElFKAzjodj_8", - "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" - ], - "resourceType" : "Device" - }, - { - "extensions" : [ - ], "fullUrl" : "urn:uuid:43f1180e-d7c0-5797-9e48-0c4313172870", "identifiers" : [ @@ -486,27 +423,6 @@ { "extensions" : [ - ], - "fullUrl" : "urn:uuid:08844702-36cb-57ff-b249-2b1b843fb79f", - "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:s8buBEyG4yRzKd2hA02jUKfwT2IN5N5psYD2moM7mb4" - ], - "resourceType" : "Device" - }, - { - "extensions" : [ - - ], - "fullUrl" : "urn:uuid:965a804c-2f33-5fe0-ae1e-a4a328007269", - "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:7oVlArgLSpX9m-sICbkampE5_6rdy4EpAz-xyYWON1o", - "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" - ], - "resourceType" : "Device" - }, - { - "extensions" : [ - ], "fullUrl" : "urn:uuid:8a8b3433-b274-5da2-8db1-7c0d4004f7ec", "identifiers" : [ @@ -579,27 +495,6 @@ { "extensions" : [ - ], - "fullUrl" : "urn:uuid:48aeeb20-6643-5b41-b3a3-44093a548f15", - "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:08kGbsvdtUqZumirucowZS9ePH45abfoM5O4nNX7rkk" - ], - "resourceType" : "Device" - }, - { - "extensions" : [ - - ], - "fullUrl" : "urn:uuid:480efa67-eb12-5f15-92ba-fbc30cf24d40", - "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:J9lvvDAXkS_dbdj52mxPi9OlB8TwcLXwadZ2GWu6m4Q", - "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" - ], - "resourceType" : "Device" - }, - { - "extensions" : [ - ], "fullUrl" : "urn:uuid:134073a9-d5de-5dd9-abaf-6b7bb226f0a5", "identifiers" : [ @@ -661,27 +556,6 @@ { "extensions" : [ - ], - "fullUrl" : "urn:uuid:1f896505-6996-55e4-8231-8412a4c864a8", - "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:gL3lSNl7EYteXp70F6laHYwj023D9L4lpXWNgHKH-ds" - ], - "resourceType" : "Device" - }, - { - "extensions" : [ - - ], - "fullUrl" : "urn:uuid:1fb8e303-b58a-5107-ac2d-9ddced20bb00", - "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:qYBO4DwuNe0zTKt3vV2rd6GhfJZ_a6meCVdUGWQ8Aqo", - "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" - ], - "resourceType" : "Device" - }, - { - "extensions" : [ - ], "fullUrl" : "urn:uuid:ded34666-95a9-5629-9a8a-a646a65d7949", "identifiers" : [ @@ -1150,27 +1024,6 @@ { "extensions" : [ - ], - "fullUrl" : "urn:uuid:35f19e6b-6e60-5b6c-b203-d4ac0dce18aa", - "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:Gm4hRTUp_vyKqlJoLR1QaMBMYnADSoLLNT26d8KscYA" - ], - "resourceType" : "Device" - }, - { - "extensions" : [ - - ], - "fullUrl" : "urn:uuid:f72582bb-3a7c-5255-808c-cdba39fd1a84", - "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:fKbOYBSJFXz6oCcdT3U15J88O4mc-9SuexoDJ5mI6Wc", - "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" - ], - "resourceType" : "Device" - }, - { - "extensions" : [ - ], "fullUrl" : "urn:uuid:788d39f2-4d35-55e3-a603-c312e815acc7", "identifiers" : [ @@ -1281,27 +1134,6 @@ { "extensions" : [ - ], - "fullUrl" : "urn:uuid:51571f65-d367-5848-9557-f958f42357bc", - "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:6_cJPfzFz0pYAYN9M-RGyPz5Gcabdpjvh7xr3Q2anfM" - ], - "resourceType" : "Device" - }, - { - "extensions" : [ - - ], - "fullUrl" : "urn:uuid:647ca0a1-1154-58d5-bb7c-a880387bbbcb", - "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:c8W0vHmQMLvMGY5CqBiah9DLz-rT454GqeZqtuLJrbU", - "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" - ], - "resourceType" : "Device" - }, - { - "extensions" : [ - ], "fullUrl" : "urn:uuid:8917710a-f76d-56c6-b18f-77f41a55f2c3", "identifiers" : [ @@ -1842,27 +1674,6 @@ { "extensions" : [ - ], - "fullUrl" : "urn:uuid:2a8208fd-d3b8-5a36-8e6c-fe64275ae3da", - "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:sCbUtg1XzO_e542E4iGvl-7azN_HrA-xeJY-_lKT4mU" - ], - "resourceType" : "Device" - }, - { - "extensions" : [ - - ], - "fullUrl" : "urn:uuid:e34dda89-a30e-5394-b8ee-b0595e1dd7c7", - "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:0eQT9MSgmDUzAt5YAOtzBtq0j7yF5fxtUi1dn7uOCSs", - "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" - ], - "resourceType" : "Device" - }, - { - "extensions" : [ - ], "fullUrl" : "urn:uuid:056345d7-1620-5265-8d21-48f208bb6912", "identifiers" : [ @@ -1923,27 +1734,6 @@ { "extensions" : [ - ], - "fullUrl" : "urn:uuid:590dd017-f9f1-5627-abdc-b1f47959e10e", - "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:dsehRkerbhq5Zpa3OMFFW-A4luy7TMC5YMDHAuSpjmQ" - ], - "resourceType" : "Device" - }, - { - "extensions" : [ - - ], - "fullUrl" : "urn:uuid:4f6c6282-7153-5005-8765-7a6ad1ac2428", - "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:Xco8n8XZVuOnolvaApgk2zQXo6uD_kN4mInjVU4YArw", - "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" - ], - "resourceType" : "Device" - }, - { - "extensions" : [ - ], "fullUrl" : "urn:uuid:72e479ff-2837-5a91-b3ca-206efadd6c57", "identifiers" : [ @@ -2005,27 +1795,6 @@ { "extensions" : [ - ], - "fullUrl" : "urn:uuid:18fba38a-2ee6-5140-80f2-d84f938266b4", - "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:s6mSUHde0SIpXeVJUkt29HnsauT6t_jVKVJw-KRRbK0" - ], - "resourceType" : "Device" - }, - { - "extensions" : [ - - ], - "fullUrl" : "urn:uuid:d21d9031-3216-5431-b57f-1b2afa147c46", - "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:cipjXhgIzQYdg8Q3ubLkiAipoA0S6MXNH1ydOvAju78", - "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" - ], - "resourceType" : "Device" - }, - { - "extensions" : [ - ], "fullUrl" : "urn:uuid:e961aa09-3fec-59b1-aab9-bb89371fb1d5", "identifiers" : [ @@ -2149,16 +1918,16 @@ ] }, - "writer-device-classification" : { + "writer-foreign-application" : { "entries" : [ { "extensions" : [ "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" ], - "fullUrl" : "urn:uuid:1f546d61-156c-5bf0-80d4-95941c18de10", + "fullUrl" : "urn:uuid:a95889d1-0d54-516b-a6a9-a52b2bb1809f", "identifiers" : [ - "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:81UrlZhjo86nQB0UCszGzlJj2_LcPZVTZ_vC9OUQg3w", - "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:mFNEqBFhJaRsanQgDqFYN3IQM_vyL46YEvVV1uWOyw8" + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:AJz4f8aqK4pJ400P46nAgpmEFAIsR2Ysx4Q2mjQi_vo", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:pqCLAAGFRwSLHZRIbv_m2xU_YzPozJNYZbzOJe4paZI" ], "resourceType" : "Observation" }, @@ -2166,9 +1935,9 @@ "extensions" : [ ], - "fullUrl" : "urn:uuid:4d25df34-97c0-5441-a4e4-74e7de79ed10", + "fullUrl" : "urn:uuid:0d697d80-71e1-5ba7-a59c-41877b725984", "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:KOTseOdrwvtSgbaOq5n_Uytq3S3yzISvXl3KuiKTqFc", + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:nRttzmH0-qkfZHsgJN7-w0HnszZ1o6dXmcMq1nirLxo", "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" ], "resourceType" : "Device" @@ -2177,9 +1946,9 @@ "extensions" : [ ], - "fullUrl" : "urn:uuid:695eb08b-1ea0-57d4-ba75-ef39692fb400", + "fullUrl" : "urn:uuid:caa54c64-62e2-5f87-8a52-d461ce1e3265", "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:uTK8EAl121dqWmzpnRKwr2aIjkjsxLoOMGHTbDWuxe8" + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:R8jE6x3KkPw3WilQx6hegDC7fpB79JyXiIxA2ymK6t0" ], "resourceType" : "Device" }, @@ -2187,9 +1956,9 @@ "extensions" : [ ], - "fullUrl" : "urn:uuid:bdd116c3-04dd-5a9e-83c8-047e61d5efbc", + "fullUrl" : "urn:uuid:acec87ec-7a33-5a2e-8eb0-ba6e5c2da101", "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:YhDFNeOk54-8CpHFrvZQ58vSLNo5h_95dRECs3Iv05g", + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:m8Bs7JWk3X2B-rQkZWnNXymQNjLxPLYM0j_6n_lhCG4", "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" ], "resourceType" : "Device" @@ -2198,37 +1967,9 @@ "extensions" : [ ], - "fullUrl" : "urn:uuid:85f263ec-1ec6-58b5-887b-39cb81f5c339", - "identifiers" : [ - - ], - "resourceType" : "Provenance" - } - ], - "warnings" : [ - - ] - }, - "writer-device-classification-without-recording-device" : { - "entries" : [ - { - "extensions" : [ - "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" - ], - "fullUrl" : "urn:uuid:a86c10b2-c5d4-5e32-b20a-acf1f3d92c1b", - "identifiers" : [ - "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:KvwGqiFmJzXnyA32l_7VSMr9nQsORddnye-BgiPFpg0", - "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:YU4KNVWRqlp9mfF8E5Hpl-8cZ_v8_2XLdpuWi3I7vtg" - ], - "resourceType" : "Observation" - }, - { - "extensions" : [ - - ], - "fullUrl" : "urn:uuid:f44a6514-7428-56e9-83e4-5c7ca029fe50", + "fullUrl" : "urn:uuid:6dda8ddb-7e62-5220-b3be-1bda46fc5607", "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:u9JvTYLnr4RT7IvVJoJgb76cGDJ-tfwIHsqeaQrBSBE" + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:HA3QVfGVZkJ_eAJqmDQrBdEo-IavSPptqY5CoENRS-k" ], "resourceType" : "Device" }, @@ -2236,10 +1977,10 @@ "extensions" : [ ], - "fullUrl" : "urn:uuid:cc6451d0-7738-56a2-8df2-ab4cbdc8d4a6", + "fullUrl" : "urn:uuid:4b4f451f-5741-5465-9043-2565a381e500", "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:-CyTyjpnePQUmb6-iYUJ-SQLUuAbAHLvYKiaBYtxpwg", - "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:MuXiWtyyfMnkHkYaZ_QJitDcMiXEFWtxTLwxVJcyYIQ", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" ], "resourceType" : "Device" }, @@ -2247,7 +1988,7 @@ "extensions" : [ ], - "fullUrl" : "urn:uuid:31bc8e36-6ffe-5852-8126-3c045cfee93a", + "fullUrl" : "urn:uuid:ed4de8c5-4bf5-5b2f-b948-5592de94fe86", "identifiers" : [ ], @@ -2258,16 +1999,16 @@ ] }, - "writer-foreign-application" : { + "writer-host-equals-converter-host" : { "entries" : [ { "extensions" : [ "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" ], - "fullUrl" : "urn:uuid:a95889d1-0d54-516b-a6a9-a52b2bb1809f", + "fullUrl" : "urn:uuid:5599a011-2c26-59bb-a95c-40de982c2253", "identifiers" : [ - "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:AJz4f8aqK4pJ400P46nAgpmEFAIsR2Ysx4Q2mjQi_vo", - "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:pqCLAAGFRwSLHZRIbv_m2xU_YzPozJNYZbzOJe4paZI" + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:XmujUDtBGLEON9ZBNR4qUb1jXIXyx_J8pugN6uU1dvo", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:N1bsPg5Tpt9wBEW0ki5-9c1RxomFVnpucNSIymcJKFQ" ], "resourceType" : "Observation" }, @@ -2275,9 +2016,9 @@ "extensions" : [ ], - "fullUrl" : "urn:uuid:0d697d80-71e1-5ba7-a59c-41877b725984", + "fullUrl" : "urn:uuid:9274a9b9-9a8b-5efc-af2d-304e81d0b30e", "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:nRttzmH0-qkfZHsgJN7-w0HnszZ1o6dXmcMq1nirLxo", + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:5GB6sZS_7W5Cgk-hDHObBDOz89ZpPK6EkdTRyahQK1o", "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" ], "resourceType" : "Device" @@ -2286,9 +2027,9 @@ "extensions" : [ ], - "fullUrl" : "urn:uuid:caa54c64-62e2-5f87-8a52-d461ce1e3265", + "fullUrl" : "urn:uuid:43810cf8-8b6e-51f8-853b-664c10277672", "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:R8jE6x3KkPw3WilQx6hegDC7fpB79JyXiIxA2ymK6t0" + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:w3TNXrnA2C6WOf_hwvPqROcYiOlEqWVdnCx1uQrEGcc" ], "resourceType" : "Device" }, @@ -2296,9 +2037,9 @@ "extensions" : [ ], - "fullUrl" : "urn:uuid:acec87ec-7a33-5a2e-8eb0-ba6e5c2da101", + "fullUrl" : "urn:uuid:64a0a45c-e646-56fe-9e28-1b3c15a5ffeb", "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:m8Bs7JWk3X2B-rQkZWnNXymQNjLxPLYM0j_6n_lhCG4", + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:VmrsaBJYNbc7lxK9uRsEZEblajKYCiXbzGxNr90XCSY", "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" ], "resourceType" : "Device" @@ -2307,19 +2048,9 @@ "extensions" : [ ], - "fullUrl" : "urn:uuid:6dda8ddb-7e62-5220-b3be-1bda46fc5607", - "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:HA3QVfGVZkJ_eAJqmDQrBdEo-IavSPptqY5CoENRS-k" - ], - "resourceType" : "Device" - }, - { - "extensions" : [ - - ], - "fullUrl" : "urn:uuid:4b4f451f-5741-5465-9043-2565a381e500", + "fullUrl" : "urn:uuid:a7bdd03c-01d1-5fa1-b065-2b5de07354d1", "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:MuXiWtyyfMnkHkYaZ_QJitDcMiXEFWtxTLwxVJcyYIQ", + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:L-7r74u94S5VQCgUyZqLO8yPIUvCmcsNpTlwDPgkPpI", "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" ], "resourceType" : "Device" @@ -2328,7 +2059,7 @@ "extensions" : [ ], - "fullUrl" : "urn:uuid:ed4de8c5-4bf5-5b2f-b948-5592de94fe86", + "fullUrl" : "urn:uuid:99b14254-dd46-5ebd-9052-73e667e3b3fc", "identifiers" : [ ], @@ -2339,16 +2070,16 @@ ] }, - "writer-host-equals-converter-host" : { + "writer-omitted" : { "entries" : [ { "extensions" : [ "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" ], - "fullUrl" : "urn:uuid:5599a011-2c26-59bb-a95c-40de982c2253", + "fullUrl" : "urn:uuid:1f546d61-156c-5bf0-80d4-95941c18de10", "identifiers" : [ - "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:XmujUDtBGLEON9ZBNR4qUb1jXIXyx_J8pugN6uU1dvo", - "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:N1bsPg5Tpt9wBEW0ki5-9c1RxomFVnpucNSIymcJKFQ" + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:81UrlZhjo86nQB0UCszGzlJj2_LcPZVTZ_vC9OUQg3w", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:mFNEqBFhJaRsanQgDqFYN3IQM_vyL46YEvVV1uWOyw8" ], "resourceType" : "Observation" }, @@ -2356,9 +2087,9 @@ "extensions" : [ ], - "fullUrl" : "urn:uuid:9274a9b9-9a8b-5efc-af2d-304e81d0b30e", + "fullUrl" : "urn:uuid:4d25df34-97c0-5441-a4e4-74e7de79ed10", "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:5GB6sZS_7W5Cgk-hDHObBDOz89ZpPK6EkdTRyahQK1o", + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:KOTseOdrwvtSgbaOq5n_Uytq3S3yzISvXl3KuiKTqFc", "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" ], "resourceType" : "Device" @@ -2367,9 +2098,9 @@ "extensions" : [ ], - "fullUrl" : "urn:uuid:43810cf8-8b6e-51f8-853b-664c10277672", + "fullUrl" : "urn:uuid:695eb08b-1ea0-57d4-ba75-ef39692fb400", "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:w3TNXrnA2C6WOf_hwvPqROcYiOlEqWVdnCx1uQrEGcc" + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:uTK8EAl121dqWmzpnRKwr2aIjkjsxLoOMGHTbDWuxe8" ], "resourceType" : "Device" }, @@ -2377,9 +2108,9 @@ "extensions" : [ ], - "fullUrl" : "urn:uuid:64a0a45c-e646-56fe-9e28-1b3c15a5ffeb", + "fullUrl" : "urn:uuid:bdd116c3-04dd-5a9e-83c8-047e61d5efbc", "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:VmrsaBJYNbc7lxK9uRsEZEblajKYCiXbzGxNr90XCSY", + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:YhDFNeOk54-8CpHFrvZQ58vSLNo5h_95dRECs3Iv05g", "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" ], "resourceType" : "Device" @@ -2388,10 +2119,37 @@ "extensions" : [ ], - "fullUrl" : "urn:uuid:a7bdd03c-01d1-5fa1-b065-2b5de07354d1", + "fullUrl" : "urn:uuid:85f263ec-1ec6-58b5-887b-39cb81f5c339", "identifiers" : [ - "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:L-7r74u94S5VQCgUyZqLO8yPIUvCmcsNpTlwDPgkPpI", - "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "writer-omitted-without-recording-device" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:a86c10b2-c5d4-5e32-b20a-acf1f3d92c1b", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:KvwGqiFmJzXnyA32l_7VSMr9nQsORddnye-BgiPFpg0", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:YU4KNVWRqlp9mfF8E5Hpl-8cZ_v8_2XLdpuWi3I7vtg" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:f44a6514-7428-56e9-83e4-5c7ca029fe50", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:u9JvTYLnr4RT7IvVJoJgb76cGDJ-tfwIHsqeaQrBSBE" ], "resourceType" : "Device" }, @@ -2399,7 +2157,18 @@ "extensions" : [ ], - "fullUrl" : "urn:uuid:99b14254-dd46-5ebd-9052-73e667e3b3fc", + "fullUrl" : "urn:uuid:cc6451d0-7738-56a2-8df2-ab4cbdc8d4a6", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:-CyTyjpnePQUmb6-iYUJ-SQLUuAbAHLvYKiaBYtxpwg", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:31bc8e36-6ffe-5852-8126-3c045cfee93a", "identifiers" : [ ], diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/two-study-enrollments.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/two-study-enrollments.json index 72b50957d..4c09161bc 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/two-study-enrollments.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/two-study-enrollments.json @@ -567,142 +567,6 @@ ] } }, - { - "extension" : [ - { - "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", - "valueIdentifier" : { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:sCbUtg1XzO_e542E4iGvl-7azN_HrA-xeJY-_lKT4mU" - } - } - ], - "fullUrl" : "urn:uuid:2a8208fd-d3b8-5a36-8e6c-fe64275ae3da", - "resource" : { - "identifier" : [ - { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:sCbUtg1XzO_e542E4iGvl-7azN_HrA-xeJY-_lKT4mU" - } - ], - "meta" : { - "profile" : [ - "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" - ] - }, - "modelNumber" : "iPhone17,1", - "resourceType" : "Device", - "status" : "active", - "version" : [ - { - "type" : { - "coding" : [ - { - "code" : "os-version", - "display" : "Operating system version", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" - } - ] - }, - "value" : "26.1.0" - } - ] - } - }, - { - "extension" : [ - { - "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", - "valueIdentifier" : { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:0eQT9MSgmDUzAt5YAOtzBtq0j7yF5fxtUi1dn7uOCSs" - } - } - ], - "fullUrl" : "urn:uuid:e34dda89-a30e-5394-b8ee-b0595e1dd7c7", - "resource" : { - "deviceName" : [ - { - "name" : "Example Writer", - "type" : "user-friendly-name" - } - ], - "identifier" : [ - { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:0eQT9MSgmDUzAt5YAOtzBtq0j7yF5fxtUi1dn7uOCSs" - }, - { - "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", - "type" : { - "coding" : [ - { - "code" : "apple-bundle-id", - "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" - } - ] - }, - "value" : "org.example.writer" - } - ], - "meta" : { - "profile" : [ - "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" - ] - }, - "parent" : { - "reference" : "urn:uuid:2a8208fd-d3b8-5a36-8e6c-fe64275ae3da" - }, - "resourceType" : "Device", - "status" : "active", - "version" : [ - { - "type" : { - "coding" : [ - { - "code" : "531975", - "display" : "MDC_ID_PROD_SPEC_SW", - "system" : "urn:iso:std:iso:11073:10101" - } - ] - }, - "value" : "42" - } - ] - } - }, { "extension" : [ { @@ -750,22 +614,6 @@ ], "entity" : [ { - "agent" : [ - { - "type" : { - "coding" : [ - { - "code" : "author", - "display" : "Author", - "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" - } - ] - }, - "who" : { - "reference" : "urn:uuid:e34dda89-a30e-5394-b8ee-b0595e1dd7c7" - } - } - ], "role" : "source", "what" : { "identifier" : { diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/udi-disclosure.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/udi-disclosure.json index 15c50ec46..0bca954be 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/udi-disclosure.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/udi-disclosure.json @@ -356,142 +356,6 @@ ] } }, - { - "extension" : [ - { - "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", - "valueIdentifier" : { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:dsehRkerbhq5Zpa3OMFFW-A4luy7TMC5YMDHAuSpjmQ" - } - } - ], - "fullUrl" : "urn:uuid:590dd017-f9f1-5627-abdc-b1f47959e10e", - "resource" : { - "identifier" : [ - { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:dsehRkerbhq5Zpa3OMFFW-A4luy7TMC5YMDHAuSpjmQ" - } - ], - "meta" : { - "profile" : [ - "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" - ] - }, - "modelNumber" : "iPhone17,1", - "resourceType" : "Device", - "status" : "active", - "version" : [ - { - "type" : { - "coding" : [ - { - "code" : "os-version", - "display" : "Operating system version", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" - } - ] - }, - "value" : "26.1.0" - } - ] - } - }, - { - "extension" : [ - { - "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", - "valueIdentifier" : { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:Xco8n8XZVuOnolvaApgk2zQXo6uD_kN4mInjVU4YArw" - } - } - ], - "fullUrl" : "urn:uuid:4f6c6282-7153-5005-8765-7a6ad1ac2428", - "resource" : { - "deviceName" : [ - { - "name" : "Example Writer", - "type" : "user-friendly-name" - } - ], - "identifier" : [ - { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:Xco8n8XZVuOnolvaApgk2zQXo6uD_kN4mInjVU4YArw" - }, - { - "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", - "type" : { - "coding" : [ - { - "code" : "apple-bundle-id", - "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" - } - ] - }, - "value" : "org.example.writer" - } - ], - "meta" : { - "profile" : [ - "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" - ] - }, - "parent" : { - "reference" : "urn:uuid:590dd017-f9f1-5627-abdc-b1f47959e10e" - }, - "resourceType" : "Device", - "status" : "active", - "version" : [ - { - "type" : { - "coding" : [ - { - "code" : "531975", - "display" : "MDC_ID_PROD_SPEC_SW", - "system" : "urn:iso:std:iso:11073:10101" - } - ] - }, - "value" : "42" - } - ] - } - }, { "extension" : [ { @@ -539,22 +403,6 @@ ], "entity" : [ { - "agent" : [ - { - "type" : { - "coding" : [ - { - "code" : "author", - "display" : "Author", - "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" - } - ] - }, - "who" : { - "reference" : "urn:uuid:4f6c6282-7153-5005-8765-7a6ad1ac2428" - } - } - ], "role" : "source", "what" : { "identifier" : { diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/workout-route.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/workout-route.json index 35bf63aca..2f305869c 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/workout-route.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/workout-route.json @@ -357,142 +357,6 @@ ] } }, - { - "extension" : [ - { - "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", - "valueIdentifier" : { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:s6mSUHde0SIpXeVJUkt29HnsauT6t_jVKVJw-KRRbK0" - } - } - ], - "fullUrl" : "urn:uuid:18fba38a-2ee6-5140-80f2-d84f938266b4", - "resource" : { - "identifier" : [ - { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:s6mSUHde0SIpXeVJUkt29HnsauT6t_jVKVJw-KRRbK0" - } - ], - "meta" : { - "profile" : [ - "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" - ] - }, - "modelNumber" : "iPhone17,1", - "resourceType" : "Device", - "status" : "active", - "version" : [ - { - "type" : { - "coding" : [ - { - "code" : "os-version", - "display" : "Operating system version", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" - } - ] - }, - "value" : "26.1.0" - } - ] - } - }, - { - "extension" : [ - { - "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", - "valueIdentifier" : { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:cipjXhgIzQYdg8Q3ubLkiAipoA0S6MXNH1ydOvAju78" - } - } - ], - "fullUrl" : "urn:uuid:d21d9031-3216-5431-b57f-1b2afa147c46", - "resource" : { - "deviceName" : [ - { - "name" : "Example Writer", - "type" : "user-friendly-name" - } - ], - "identifier" : [ - { - "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", - "type" : { - "coding" : [ - { - "code" : "device-snapshot", - "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" - } - ] - }, - "value" : "v0:test:1:cipjXhgIzQYdg8Q3ubLkiAipoA0S6MXNH1ydOvAju78" - }, - { - "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", - "type" : { - "coding" : [ - { - "code" : "apple-bundle-id", - "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" - } - ] - }, - "value" : "org.example.writer" - } - ], - "meta" : { - "profile" : [ - "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" - ] - }, - "parent" : { - "reference" : "urn:uuid:18fba38a-2ee6-5140-80f2-d84f938266b4" - }, - "resourceType" : "Device", - "status" : "active", - "version" : [ - { - "type" : { - "coding" : [ - { - "code" : "531975", - "display" : "MDC_ID_PROD_SPEC_SW", - "system" : "urn:iso:std:iso:11073:10101" - } - ] - }, - "value" : "42" - } - ] - } - }, { "extension" : [ { @@ -540,22 +404,6 @@ ], "entity" : [ { - "agent" : [ - { - "type" : { - "coding" : [ - { - "code" : "author", - "display" : "Author", - "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" - } - ] - }, - "who" : { - "reference" : "urn:uuid:d21d9031-3216-5431-b57f-1b2afa147c46" - } - } - ], "role" : "source", "what" : { "identifier" : { diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-device-classification-without-recording-device.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-omitted-without-recording-device.json similarity index 100% rename from Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-device-classification-without-recording-device.json rename to Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-omitted-without-recording-device.json diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-device-classification.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-omitted.json similarity index 96% rename from Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-device-classification.json rename to Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-omitted.json index 6f6dd8a84..c3fa5b822 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-device-classification.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-omitted.json @@ -398,22 +398,6 @@ ], "entity" : [ { - "agent" : [ - { - "type" : { - "coding" : [ - { - "code" : "author", - "display" : "Author", - "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" - } - ] - }, - "who" : { - "reference" : "urn:uuid:4d25df34-97c0-5441-a4e4-74e7de79ed10" - } - } - ], "role" : "source", "what" : { "identifier" : { diff --git a/Tests/GroveHealthKitFHIRTests/StoredSampleFixturesTests.swift b/Tests/GroveHealthKitFHIRTests/StoredSampleFixturesTests.swift index 848d1cb13..025c36832 100644 --- a/Tests/GroveHealthKitFHIRTests/StoredSampleFixturesTests.swift +++ b/Tests/GroveHealthKitFHIRTests/StoredSampleFixturesTests.swift @@ -98,7 +98,7 @@ struct StoredSampleFixturesTests { @Test("The chosen UUID and writer are what the converter sees") func converterReadsTheStoredFacts() throws { let sample = try GoldenFixtures.heartRate(uuid: Self.uuid, device: GoldenFixtures.watch, writer: Self.writer) - let context = try GoldenFixtures.context(sequence: 250) + let context = try GoldenFixtures.context(sequence: 250, .applicationWriter) let conversion = try HealthKitConverter().convert(sample, context: context).primary #expect(conversion.source.uuid == Self.uuid) From 7af0c59ed437a7281613d76551bd143f1fe54699 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 12:59:12 +0200 Subject: [PATCH 021/220] Tell Same-Size Application Sets Apart and Pin the Context Fingerprint G2 review fix round (final-spec 2.4, the context fingerprint; G3 of (f)). The fingerprint tests could not tell two .applications sets of the same size apart: G3 paired sets of sizes 1, 2 and 0, and the membership test compared 24 members with 23. A fingerprint that kept only the member count passed the whole suite (mutation M10, re-verified at 55b9fc50 together with M24: 272 total, 270 passed, 2 skipped, 0 failed), and would reuse a reserved event for different bytes when a deployment swaps one listed application for another. Tests (HealthKitFHIRExporterFingerprintTests): - G3 gains "writer applications other" ({org.example.other}), the size of "writer applications" ({org.example.writer}) with another member. - applicationSetsFingerprintByMembership also swaps a member for another (app0 -> app24) and expects a new fingerprint. - New known-answer test: a fixed context (explicit output revisions 1/2, the test identity scope and subject, writer .applications({org.example.caff, org.example.cafe + U+0301})) has writer parts [applications, 2, org.example.cafe + U+0301, org.example.caff], compared byte for byte, and the fingerprint Y9AmAuXc9kZTd8ZjijBhBS7QD_7A8w4YKQLk7RXFRig. A reservation keeps the fingerprint it was made under across launches and app updates, so a build that derives the same context's fingerprint differently re-sequences every pending reservation on redelivery; the known answer makes such a change deliberate. The decomposed member separates UTF-8 byte order from Swift's String order. Doc (WriterPolicy fingerprintParts): "equal sets fingerprint equally whatever their insertion order or the platform's collation" overstated the guarantee. Set equality is canonical equivalence while the fingerprint frames raw UTF-8 (probe: Set(["org.caf\u{e9}"]) == Set(["org.cafe\u{301}"]) is true, their sorted parts compare == as Strings but differ as UTF-8). It now says sets of the same strings, byte for byte, fingerprint equally, and that canonically equal spellings fingerprint apart (a new sequence, never a reuse). Mutation proof (each applied alone to this tree, full GroveHealthKitFHIRTests on macOS, then restored and compared byte-equal; unmutated: 274 total, 272 passed, 2 skipped): - M09 (count dropped: ["applications"] + sorted): 1 failed, the known-answer test (parts and fingerprint). - M10 (members dropped: ["applications", count]): 3 failed, the known-answer test, G3 ("writer applications other shares its fingerprint with writer applications") and the membership test ("another member in its place"). - M14 (bundleIdentifiers.sorted(), Swift String order): 1 failed, the known-answer test (parts in the other order, another fingerprint). Output unchanged (no source change beyond a doc comment; goldens untouched). Co-Authored-By: Claude Opus 5.5 --- .../HealthKitFHIRExporter+Fingerprint.swift | 6 +++-- ...ealthKitFHIRExporterFingerprintTests.swift | 26 ++++++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift index 06eee406d..970292167 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift @@ -125,8 +125,10 @@ extension Subject: ExchangeContextFingerprinted { @available(iOS 18, macOS 15, watchOS 11, *) extension HealthKitFHIRExporter.WriterPolicy: ExchangeContextFingerprinted { /// The tag, then for an application set its count, which fixes how many parts follow, and its members in UTF-8 - /// byte order, so equal sets fingerprint equally whatever their insertion order or the platform's collation. A - /// closure enters by its presence only; how it classifies is the caller's to keep stable. + /// byte order, so sets of the same strings, byte for byte, fingerprint equally whatever their insertion order. + /// `Set` equality is canonical equivalence, so two sets that spell a member in different Unicode normalization + /// forms compare equal yet fingerprint apart: a new sequence, never a reused one. A closure enters by its + /// presence only; how it classifies is the caller's to keep stable. var fingerprintParts: [String] { switch self { case .omit: diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFingerprintTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFingerprintTests.swift index fed7cc69e..58664c2a3 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFingerprintTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFingerprintTests.swift @@ -44,6 +44,8 @@ struct HealthKitFHIRExporterFingerprintTests { ("route", { $0.route = .authorized }), ("legacyBundleID", { $0.legacyBundleID = .healthKitUUID }), ("writer applications", { $0.writer = .applications(["org.example.writer"]) }), + // The size of the set above with another member: only the members tell the two apart. + ("writer applications other", { $0.writer = .applications(["org.example.other"]) }), ("writer applications member", { $0.writer = .applications(["org.example.writer", "org.example.other"]) }), ("writer applications empty", { $0.writer = .applications([]) }), ("writer classify", { $0.writer = .classify { _ in .application } }), @@ -155,7 +157,29 @@ struct HealthKitFHIRExporterFingerprintTests { try Fixtures.exporter { $0.writer = .applications(bundleIdentifiers) }.context.request(for: key).fingerprint } #expect(try fingerprint(inserted) == fingerprint(reversed)) - #expect(try fingerprint(inserted) != fingerprint(inserted.subtracting(["org.example.app0"]))) + #expect(try fingerprint(inserted) != fingerprint(inserted.subtracting(["org.example.app0"])), "a member less") + #expect( + try fingerprint(inserted) != fingerprint(inserted.subtracting(["org.example.app0"]).union(["org.example.app24"])), + "another member in its place" + ) + } + + /// A reservation keeps the fingerprint it was made under, and every later export compares against it, across + /// launches and app updates: a build that derives the same context's fingerprint differently gives every pending + /// reservation a new sequence on redelivery, so the derivation changes only on purpose. One member of the + /// application set is not in Unicode normalization form C, so its UTF-8 byte order differs from Swift's `String` + /// order. + @Test("A fixed context fingerprints to a known answer, its application set as tag, count and members in UTF-8 byte order") + func contextFingerprintIsAKnownAnswer() throws { + let decomposed = "org.example.cafe\u{301}" + let writer = HealthKitFHIRExporter.WriterPolicy.applications(["org.example.caff", decomposed]) + let expectedParts = ["applications", "2", decomposed, "org.example.caff"] + #expect(writer.fingerprintParts.map { Array($0.utf8) } == expectedParts.map { Array($0.utf8) }) + let exporter = try Fixtures.exporter(try Fixtures.producer(sequencer: .inMemory()), revisions: .init(assembler: 1, healthKit: 2)) { + $0.writer = writer + } + let key = ExchangeEventKey.active(type: .heartRate, uuid: GoldenFixtures.uuid(1)) + #expect(exporter.context.request(for: key).fingerprint == "Y9AmAuXc9kZTd8ZjijBhBS7QD_7A8w4YKQLk7RXFRig") } @Test("G3b: the fingerprint covers every stored option, each under its own name and with its own value") From 8e348a7b03407c57b06358cc361a69e91a98e90c Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 12:59:33 +0200 Subject: [PATCH 022/220] Pin the Writer Record Under Every Writer Policy and State the Writer's Exceptions G2 review fix round (final-spec (c) 3.1; audit ledger 3, confirmed finding 8, the HealthKitWriter docs; IG ig-pin healthkit/input/pagecontent/mapping.md:44-47 for the writer-record identity). Writer record. G2 moved the sync-identity golden to an explicit .applicationWriter and every converter test of the sync pair uses an unattributed sample (empty bundle identifier), so nothing pinned that an attributed sample from a source nobody classified still carries its writer-record identity and version. A SourceFacts that derived the writer record only under .application (mutation M24) passed the whole suite (re-verified at 55b9fc50 together with M10: 272 total, 270 passed, 2 skipped, 0 failed). New test in HealthKitFHIRExporterWriterTests: a foreign-writer heart rate with the sync pair (sync-abc, version 3) exported under Options() and under .omit, .applications listing it, listing another, listing none, .classify { .omit } and .classify { .application } carries exactly one writer-record identifier, equal to the identity scope's writerRecord(org.example.writer under the Apple bundle-identifier system, sync-abc), and the version extension "3". The WriterPolicy doc now says the sync pair travels as the writer-record identity under every policy. Docs (WriterPolicy.applications, HealthKitWriter.application): a classified source with a blank name or bundle identifier states no writer, and one whose bundle identifier is not a valid Apple bundle identifier is refused with HealthKitConversionError.sourceApplicationInvalid (SourceFacts.writer; the host can never fail there). The goldens writer-blank-name-with-sync-identity and GoldenGraphTests.invalidWriterBundleIdentifierIsRefused pin both. ProducerSurfaceTests.writerNodes ended with a conversion that once pinned .device and, after G2, repeated the test init's default .omit on an unattributed sample, so its two expectations pinned nothing. It now pins the other half of the test's claim: an attributed sample whose source the caller classifies as an application carries both writer nodes, and repository ids name each. Mutation proof (applied alone, full GroveHealthKitFHIRTests on macOS, then restored and compared byte-equal; unmutated: 274 total, 272 passed, 2 skipped): M24 fails the new writer-record test under the default, omit, applications listing another, no applications and classified as omitted (no writer-record identifier, no version); the two policies that classify the source as an application still pass, as they should. Output unchanged (goldens untouched; source changes are doc comments only). Co-Authored-By: Claude Opus 5.5 --- .../HealthKitFHIRDisclosurePolicies.swift | 4 ++- .../HealthKitFHIRExporter+Options.swift | 7 ++-- .../HealthKitFHIRExporterWriterTests.swift | 35 +++++++++++++++++++ .../ProducerAlignmentTests.swift | 13 +++++-- 4 files changed, 53 insertions(+), 6 deletions(-) diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRDisclosurePolicies.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRDisclosurePolicies.swift index 963b677f0..53b490937 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRDisclosurePolicies.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRDisclosurePolicies.swift @@ -30,7 +30,9 @@ public enum HealthKitUDIDisclosurePolicy: Hashable, Sendable { public enum HealthKitWriter: Hashable, Sendable { /// The source is an application: it is stated with its name, bundle identifier and version, all copied /// from the sample's `HKSourceRevision`, and the host it ran on, as the graph's `ExchangeGraphNode.writer` - /// and `ExchangeGraphNode.writerHost` snapshots and the Provenance author. + /// and `ExchangeGraphNode.writerHost` snapshots and the Provenance author. A source with a blank name or + /// bundle identifier states no writer, and one whose bundle identifier is not a valid Apple bundle + /// identifier is refused with ``HealthKitConversionError/sourceApplicationInvalid``. case application /// No writer is stated, and the Provenance names no author. case omit diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift index e530a68e9..aa4eef488 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift @@ -53,13 +53,16 @@ extension HealthKitFHIRExporter { /// guide forbids classifying it from the bundle identifier's shape, the source name or the product type: /// a source nobody classified states no writer. Only the caller's explicit classification states one. The /// physical unit a sample was measured on is the recording Device, which ``RecordingDevicePolicy`` - /// resolves from `HKDevice` whatever this policy says. + /// resolves from `HKDevice` whatever this policy says. A sample's sync identifier and version likewise + /// travel as its writer-record identity, scoped to the source's bundle identifier, under every policy. public enum WriterPolicy: Sendable { /// No writer is stated, and the Provenance names no author. The default. case omit /// A source whose bundle identifier is one of these, which the caller knows to be applications, is /// stated as that application, with its name, bundle identifier and `HKSourceRevision.version` and - /// the host it ran on. Every other source states no writer. + /// the host it ran on. Every other source states no writer. A listed source with a blank name or bundle + /// identifier states none either, and one whose bundle identifier is not a valid Apple bundle identifier + /// is refused with ``HealthKitConversionError/sourceApplicationInvalid``. case applications(Set) /// The caller classifies each source. The closure must be a pure function of the source and stable /// across application versions: the context fingerprint records only that a closure classifies, so diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterWriterTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterWriterTests.swift index 29b04f661..bce7609f8 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterWriterTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterWriterTests.swift @@ -223,6 +223,41 @@ struct HealthKitFHIRExporterWriterTests { Self.statesNoWriter(try #require(exports[omitted.uuid]?.graph?.bundle), source: Self.otherApplication) } + @Test("A sample's writer-record identity and version travel whatever the writer policy says about its source") + func writerRecordTravelsUnderEveryWriterPolicy() throws { + let sample = try GoldenCase.attributedHeartRate(uuid: 0x61, writer: GoldenFixtures.foreignWriter, metadata: GoldenCase.syncMetadata) + // The writing application's bundle identifier scopes the sync identifier, whether or not the caller classified it. + let expected = try Fixtures.base.identityScope.writerRecord( + writerApplication: BusinessIdentifier( + system: IdentifierSystem(Canonicals.appleBundleIdentifierSystem), + value: GoldenFixtures.foreignWriter.bundleIdentifier + ), + writerRecordID: "sync-abc" + ) + let exporters: [(String, HealthKitFHIRExporter)] = try [ + ("the default", Fixtures.exporter()), + ("omit", Fixtures.exporter { $0.writer = .omit }), + ("applications listing it", Fixtures.exporter { $0.writer = .applications([GoldenFixtures.foreignWriter.bundleIdentifier]) }), + ("applications listing another", Fixtures.exporter { $0.writer = .applications([Self.otherApplication.bundleIdentifier]) }), + ("no applications", Fixtures.exporter { $0.writer = .applications([]) }), + ("classified as omitted", Fixtures.exporter { $0.writer = .classify { _ in .omit } }), + ("classified as an application", Fixtures.exporter { $0.writer = .classify { _ in .application } }) + ] + for (policy, exporter) in exporters { + let bundle = try #require(try Self.exports(exporter, [sample])[sample.uuid]?.graph?.bundle) + let observation = try #require(bundle.entry?.compactMap { $0.resource?.get(if: ModelsR4.Observation.self) }.first) + let writerRecords = (observation.identifier ?? []).filter { (try? RoledIdentifier($0).role) == .writerRecord } + #expect(writerRecords.map { $0.value?.value?.string } == [expected.value], "under \(policy)") + let versions = (observation.extension ?? []).filter { $0.url == Canonicals.writerRecordVersion }.map { version -> String? in + guard case .string(let value)? = version.value else { + return nil + } + return value.value?.string + } + #expect(versions == ["3"], "under \(policy)") + } + } + @Test("W4: no source file of the adapter names Apple's per-device bundle-identifier prefix") func noSourceNamesThePerDevicePrefix() throws { let sources = URL(fileURLWithPath: #filePath) diff --git a/Tests/GroveHealthKitFHIRTests/ProducerAlignmentTests.swift b/Tests/GroveHealthKitFHIRTests/ProducerAlignmentTests.swift index f0d69e3c5..43c744a7c 100644 --- a/Tests/GroveHealthKitFHIRTests/ProducerAlignmentTests.swift +++ b/Tests/GroveHealthKitFHIRTests/ProducerAlignmentTests.swift @@ -298,9 +298,16 @@ struct ProducerSurfaceTests { try HealthKitConverter().convert(Self.heartRate, context: context) } } - let conversion = try HealthKitConverter().convert(Self.heartRate, context: HealthKitConversionContext(writer: .omit)) - #expect(conversion.graphIdentifiers.writerSnapshot == nil) - #expect(conversion.graphIdentifiers.writerHostSnapshot == nil) + // Once the caller classifies an attributed sample's source as an application, the graph carries both nodes and + // a repository id names each. + let attributed = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0xC1), writer: GoldenFixtures.foreignWriter) + let context = try HealthKitConversionContext( + writer: .application, + repositoryIDs: [.writer: RepositoryID("writer-1"), .writerHost: RepositoryID("writer-host-1")] + ) + let conversion = try HealthKitConverter().convert(attributed, context: context) + #expect(conversion.graphIdentifiers.writerSnapshot != nil) + #expect(conversion.graphIdentifiers.writerHostSnapshot != nil) } @Test("A writer snapshot the converter already states is that entry, and its host goes with it") From 28f931195ec07a631f6ba836bba05b2a16688052 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 12:59:39 +0200 Subject: [PATCH 023/220] Name the Provenance Author From the Writer Snapshot Directly G2 review fix round (final-spec (c) 3.2, which deleted the recording-Device author branch). With that branch gone, ExchangeGraphAssembler.Devices.authorURL was always writer?.applicationURL: one producer (resolveDevices) and one reader (the Provenance call in assemble). The stored field is deleted; the Provenance call reads devices.writer?.applicationURL and keeps the comment that the writer application is the author and that without one the Provenance names none. The Devices doc no longer claims to say who the author is. Output unchanged, verified by the GroveHealthKitFHIR goldens (byte-equal, G17 rows untouched), the GroveSensorKitFHIR and GroveQuestionnaire suites and the healthkit conformance run below. ExchangeGraphAssembler.outputRevision stays 1. Gates for this round (at this tree; the two earlier commits of the round changed tests and doc comments only): - GroveHealthKitFHIR macOS: Passed, 274 total, 272 passed, 2 skipped (the same 2 as before), 0 failed. - GroveSensorKitFHIR macOS: Passed, 83/83. - GroveQuestionnaire macOS: Passed, 260/260. - GROVE_LOWERED_DEPLOYMENT_TARGETS=1 xcrun swift build --target GroveFHIRContract: Build complete. - swiftlint lint --strict --quiet (GroveFHIRContract, GroveHealthKitFHIR, GroveHealthKitFHIRTests): no findings. - reuse lint: compliant (2874/2874). - Scripts/validate-fhir-conformance.sh healthkit (guides: the scratchpad copy of the read-only ig-pin extract built for G2): 28 resources, "OK - all healthkit resources conform to their declared R4 profiles"; contract generator and semantic-vector checks clean. - xcodebuild docbuild GroveHealthKitFHIR (macOS): succeeded; no unresolved symbol link in GroveHealthKitFHIR or GroveFHIRContract (the new HealthKitConversionError/sourceApplicationInvalid links resolve). Size (A): code 11,142 (+1,437), public 1,006 (+133) (vs baseline Grove 9b086e60; vs 55b9fc50: code -1, public 0. Level B: code 21,204 (+1,437), public 1,909 (+133).) Co-Authored-By: Claude Opus 5.5 --- .../GroveFHIRContract/ExchangeGraphAssembler+Devices.swift | 3 +-- Sources/GroveFHIRContract/ExchangeGraphAssembler.swift | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Sources/GroveFHIRContract/ExchangeGraphAssembler+Devices.swift b/Sources/GroveFHIRContract/ExchangeGraphAssembler+Devices.swift index 220ef252d..ff0158a8c 100644 --- a/Sources/GroveFHIRContract/ExchangeGraphAssembler+Devices.swift +++ b/Sources/GroveFHIRContract/ExchangeGraphAssembler+Devices.swift @@ -84,8 +84,7 @@ extension ExchangeGraphAssembler { if draft.repositoryIDs[.writerHost] != nil, !writerEntries.contains(where: { $0 == writer?.host.identity }) { throw ExchangeAssemblyError.repositoryIDWithoutNode(.writerHost) } - // The writer application is the Provenance author; without one the Provenance names none. - return Devices(converter: converter, recording: recording, writer: writer, authorURL: writer?.applicationURL) + return Devices(converter: converter, recording: recording, writer: writer) } private func converterSnapshots( diff --git a/Sources/GroveFHIRContract/ExchangeGraphAssembler.swift b/Sources/GroveFHIRContract/ExchangeGraphAssembler.swift index d23ccd149..7ab217916 100644 --- a/Sources/GroveFHIRContract/ExchangeGraphAssembler.swift +++ b/Sources/GroveFHIRContract/ExchangeGraphAssembler.swift @@ -29,12 +29,11 @@ package struct ExchangeGraphAssembler: Sendable { let converterURL: String } - /// The device snapshots of one graph and who the Provenance names as author. + /// The device snapshots of one graph. struct Devices { let converter: ConverterSnapshots let recording: RecordingSnapshot? let writer: WriterSnapshots? - let authorURL: String? /// Every Device entry, in its fixed order. var entries: [IdentifiedDevice] { @@ -93,7 +92,8 @@ package struct ExchangeGraphAssembler: Sendable { sourceIdentifier: draft.sourceRecord.identifier.fhirIdentifier, targetURLs: outputs.map(\.url), converterURL: devices.converter.applicationURL, - authorURL: devices.authorURL, + // The writer application is the Provenance author; without one the Provenance names none. + authorURL: devices.writer?.applicationURL, recordedAt: draft.instant ) provenance.id = draft.repositoryIDs[.provenance]?.primitive From e2e5397f421b30082cda42e8dc101cc6c2941a1a Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 13:54:01 +0200 Subject: [PATCH 024/220] Compare Graph Tokens Scalar by Scalar and Keep Every U+FEFF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix-round step G3, audit ledger section 1 confirmed finding 7 (the comparator treats canonically equivalent strings as equal, every golden is ASCII) and the LosslessJSONValue BOM item of the ledger decision list. LosslessJSONValue decides ExchangeGraph.isSemanticallyEqual (the exact-retry predicate) and every golden comparison. Its synthesized equality compared strings and member names with Swift String ==, which is canonical equivalence, so "Sant\u{E9}" equalled "Sante\u{301}"; the guide's reference comparator (ig-pin Tests/test_receiver_lifecycle.py:50-60, json.loads with string lexemes, then Python ==) compares code points. And the string parser decoded each UTF-8 run with String(bytes:encoding:), which drops a leading U+FEFF, so "\u{FEFF}x" parsed as "x" (also right after an escape). - Equality is written out: strings and number lexemes compare by unicodeScalars; an object compares each member's value and the stored member name scalar by scalar (a dictionary lookup finds canonically equivalent names alike). Parsing is unchanged otherwise; two canonically equivalent member names in one object stay a duplicate, as StrictJSONScanner refuses them. - UTF-8 runs are decoded with the UTF8 codec, which keeps every scalar. - Docs: LosslessJSONValue and isSemanticallyEqual state the scalar rule. - Test harness: TokenDiff reports a member name that differs only in its scalars, and prints non-ASCII scalars as \u{...} so a failure is legible. Tests: - GoldenGraphTests.tokensCompareUnicodeScalars: precomposed vs decomposed values and member names differ (with the reported path); a leading U+FEFF, raw or after an escape, is kept; "" escaped equals the raw scalar. - New golden writer-non-ascii-name (writers group, sequence 30): the foreign application writer named "Sant\u{E9} Journal" under .applicationWriter, so a non-ASCII string is pinned in bytes. G17 row added at the current revisions (assembler 1, healthKit 2), no bump: no existing output changed. Mutation proof (each applied alone, full GroveHealthKitFHIRTests on macOS, then reverted; unmutated: 275 total, 273 passed, 2 skipped): - synthesized equality restored: fails tokensCompareUnicodeScalars ("precomposed != decomposed"). - runs drop a leading U+FEFF again: fails tokensCompareUnicodeScalars. - SourceFacts states the writer name decomposed (decomposedStringWithCanonicalMapping): fails matchesCheckedInGolden for writer-non-ascii-name at $.entry[5].resource.deviceName[0].name (golden "Sant\u{e9} Journal", actual "Sante\u{301} Journal"). Applied together with the synthesized equality, that golden passes again: only the scalar comparison catches the drift. Output diff: none. All 42 existing goldens regenerate byte-identical (TEST_RUNNER_GROVE_GOLDEN_OUTPUT_DIR outside the worktree); outlines.json only gains the writer-non-ascii-name entry. Gates: GroveHealthKitFHIR macOS 275 total, 273 passed, 2 skipped; GroveSensorKitFHIR 83/83; GroveQuestionnaire 260/260; GROVE_LOWERED_DEPLOYMENT_TARGETS=1 xcrun swift build --target GroveFHIRContract: Build complete; swiftlint --strict: no findings; reuse lint: compliant. Co-Authored-By: Claude Opus 5.5 --- .../ExchangeGraph+Equality.swift | 60 +- .../GoldenGraphCases.swift | 7 + .../GoldenGraphTests.swift | 27 +- .../GoldenOutputRevisionTests.swift | 3 +- .../Resources/Goldens/outlines.json | 81 +++ .../Goldens/writer-non-ascii-name.json | 606 ++++++++++++++++++ 6 files changed, 771 insertions(+), 13 deletions(-) create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-non-ascii-name.json diff --git a/Sources/GroveFHIRContract/ExchangeGraph+Equality.swift b/Sources/GroveFHIRContract/ExchangeGraph+Equality.swift index df197e93b..5a7be6b1c 100644 --- a/Sources/GroveFHIRContract/ExchangeGraph+Equality.swift +++ b/Sources/GroveFHIRContract/ExchangeGraph+Equality.swift @@ -9,7 +9,13 @@ import Foundation -/// A JSON document read without losing what the receiver compares: number lexemes stay text. +/// A JSON document read without losing what the receiver compares: number lexemes stay text, and strings +/// keep every Unicode scalar they were written with. +/// +/// Equality is the exchange protocol's token equality (`exchange-protocol.json` `semanticComparison`), which the +/// guide's reference comparator decides over code points: strings and member names compare scalar by scalar, so +/// canonically equivalent spellings such as `U+00E9` and `e U+0301` are different content, and nothing is normalized. +/// An object whose member names are canonically equivalent is refused as a duplicate, as `StrictJSONScanner` refuses it. indirect enum LosslessJSONValue: Equatable { case object([String: LosslessJSONValue]) case array([LosslessJSONValue]) @@ -173,15 +179,21 @@ indirect enum LosslessJSONValue: Equatable { index += 1 var scalars = String.UnicodeScalarView() var utf8Run: [UInt8] = [] + // Decoded scalar by scalar: `String(bytes:encoding:)` would drop a leading U+FEFF as a byte order mark. func flushRun() throws(ParseError) { - guard !utf8Run.isEmpty else { - return + var decoder = UTF8() + var iterator = utf8Run.makeIterator() + while true { + switch decoder.decode(&iterator) { + case .scalarValue(let scalar): + scalars.append(scalar) + case .emptyInput: + utf8Run.removeAll() + return + case .error: + throw ParseError() + } } - guard let text = String(bytes: utf8Run, encoding: .utf8) else { - throw ParseError() - } - scalars.append(contentsOf: text.unicodeScalars) - utf8Run.removeAll() } while index < bytes.count { let byte = bytes[index] @@ -258,12 +270,40 @@ indirect enum LosslessJSONValue: Equatable { } +extension LosslessJSONValue { + /// Token equality, with strings, lexemes and member names compared scalar by scalar. + static func == (lhs: LosslessJSONValue, rhs: LosslessJSONValue) -> Bool { + switch (lhs, rhs) { + case let (.object(lhs), .object(rhs)): + // A dictionary finds a member under any canonically equivalent name, so the name found is compared too. + lhs.count == rhs.count && lhs.allSatisfy { name, value in + guard let index = rhs.index(forKey: name) else { + return false + } + return rhs[index].key.unicodeScalars.elementsEqual(name.unicodeScalars) && rhs[index].value == value + } + case let (.array(lhs), .array(rhs)): + lhs == rhs + case let (.string(lhs), .string(rhs)), let (.number(lhs), .number(rhs)): + lhs.unicodeScalars.elementsEqual(rhs.unicodeScalars) + case let (.boolean(lhs), .boolean(rhs)): + lhs == rhs + case (.null, .null): + true + default: + false + } + } +} + + extension ExchangeGraph { /// Whether two graphs carry the same JSON tokens. /// /// Member order, whitespace and string escaping do not matter; a decimal lexeme is compared as - /// text, so `72` and `72.0` are different content. A retry that is equal under this comparison - /// is the exact retry the exchange protocol admits. + /// text, so `72` and `72.0` are different content, and strings compare scalar by scalar without + /// Unicode normalization. A retry that is equal under this comparison is the exact retry the + /// exchange protocol admits. public func isSemanticallyEqual(to other: ExchangeGraph) -> Bool { guard let lhs = try? LosslessJSONValue(parsing: json), let rhs = try? LosslessJSONValue(parsing: other.json) else { diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift index 900fab3c6..30827526f 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift @@ -181,6 +181,13 @@ extension GoldenCase { sequence: sequence, .applicationWriter ) + }, + // A name outside ASCII with a precomposed U+00E9: the comparison is scalar by scalar, so a decomposed + // spelling of the same name would be a different golden. + GoldenCase("writer-non-ascii-name", sequence: 30) { sequence in + var writer = GoldenFixtures.foreignWriter + writer.name = "Sant\u{E9} Journal" + return try GoldenFixtures.convert(attributedHeartRate(uuid: 30, writer: writer), sequence: sequence, .applicationWriter) } ] diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift index 957b0bffe..0e5a42bed 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift @@ -121,7 +121,8 @@ private enum TokenDiff { return difference } } - return nil + // Every value matched under a dictionary lookup, which finds canonically equivalent names alike. + return expected == actual ? nil : "\(path): a member name differs in its Unicode scalars" case let (.array(lhs), .array(rhs)): for (index, pair) in zip(lhs, rhs).enumerated() { if let difference = firstDifference(expected: pair.0, actual: pair.1, at: "\(path)[\(index)]") { @@ -138,7 +139,7 @@ private enum TokenDiff { switch value { case .object(let members): "object(\(members.count) members)" case .array(let elements): "array(\(elements.count))" - case .string(let text): "\"\(text)\"" + case .string(let text): "\"" + text.unicodeScalars.map { $0.isASCII ? String($0) : "\\u{\(String($0.value, radix: 16))}" }.joined() + "\"" case .number(let lexeme): lexeme case .boolean(let flag): "\(flag)" case .null: "null" @@ -267,6 +268,28 @@ struct GoldenGraphTests { #expect(GoldenOutline(golden, warnings: []) != GoldenOutline(longer, warnings: [])) #expect(GoldenOutline(golden, warnings: ["a"]) != GoldenOutline(golden, warnings: [])) } + + /// Strings and member names compare scalar by scalar, as the guide's reference comparator does: a canonically + /// equivalent spelling and a leading U+FEFF are different content, while a `\u` escape is the scalar it names. + @Test + func tokensCompareUnicodeScalars() throws { + func tokens(_ json: String) throws -> LosslessJSONValue { + try LosslessJSONValue(parsing: Data(json.utf8)) + } + let precomposed = try tokens(#"{"name":"Sant\#u{E9}"}"#) + let decomposed = try tokens(#"{"name":"Sante\#u{301}"}"#) + #expect(precomposed != decomposed) + #expect(TokenDiff.firstDifference(expected: precomposed, actual: decomposed) == #"$.name: golden "Sant\u{e9}", actual "Sante\u{301}""#) + #expect(try tokens(#"{"Sant\#u{E9}":1}"#) != tokens(#"{"Sante\#u{301}":1}"#)) + #expect( + TokenDiff.firstDifference(expected: try tokens(#"{"Sant\#u{E9}":1}"#), actual: try tokens(#"{"Sante\#u{301}":1}"#)) + == "$: a member name differs in its Unicode scalars" + ) + let marked = try tokens(#"{"name":"\#u{FEFF}x"}"#) + #expect(try tokens(#"{"name":"x"}"#) != marked) + #expect(try tokens(#"{"name":"\uFEFFx"}"#) == marked) + #expect(try tokens(#"["\#u{FEFF}a","\n\#u{FEFF}b"]"#) == .array([.string("\u{FEFF}a"), .string("\n\u{FEFF}b")])) + } } diff --git a/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift b/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift index cd35b7369..5f652bc71 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift @@ -63,7 +63,7 @@ struct GoldenOutputRevisionTests { GoldenRevision("heartbeat-series", digest: "fB3bdqSnBH2vJxBfzQQDFFeItPoT6Bs8Yom7uFbYS98", assembler: 1, healthKit: 2), GoldenRevision("insulin-delivery-bolus", digest: "fCw3-HgNHCW_r1bQ8bY5WiGz52iekzNbJ0-AKZp59yc", assembler: 1, healthKit: 1), GoldenRevision("native-identifier-disclosure", digest: "d0cEPkdGfs7W8CYbUpS-GDKoc64jN21WjgkWSibIAAM", assembler: 1, healthKit: 2), - GoldenRevision("outlines", digest: "cPcJEmmsQYu93MgmKbOTjuqgyorDKhDZb54gpvyroTs", assembler: 1, healthKit: 2), + GoldenRevision("outlines", digest: "IPbl39VRExwMgTppEfppx3HSBanBbsFRLVGsWo6wmxk", assembler: 1, healthKit: 2), GoldenRevision("repository-ids-on-every-node", digest: "wnO8sPt82cYYd4m50n4tycbEXWdgvNRlKjQItQI6n4Y", assembler: 1, healthKit: 1), GoldenRevision("retraction-blood-pressure", digest: "x4muVgyjqh8AfgVGhaS55MeMVmxJ58UR0hsghhedkEA", assembler: 1, healthKit: 1), GoldenRevision("retraction-electrocardiogram", digest: "JJIp4J2S4Vr0CX-d1fi3IqAmyNzuzSz4fyrF-gbrkgM", assembler: 1, healthKit: 1), @@ -81,6 +81,7 @@ struct GoldenOutputRevisionTests { GoldenRevision("writer-blank-name-with-sync-identity", digest: "eGHwwHdaM8H_QqW2kRQqNcXBj-309dPxpqy3gkXnKNU", assembler: 1, healthKit: 1), GoldenRevision("writer-foreign-application", digest: "SaD46SDNVFB6NPQJmIBglAQpwczYwAKlQvSlLl8-d24", assembler: 1, healthKit: 1), GoldenRevision("writer-host-equals-converter-host", digest: "fGxbULDNVld5Ke8SXJEiEaHwi_W-3p2KTFpG7i6jQQs", assembler: 1, healthKit: 1), + GoldenRevision("writer-non-ascii-name", digest: "J4HDch8QfPqlqhtpYfzk7ai7RSHMFIzq4LysSa-BYc4", assembler: 1, healthKit: 2), GoldenRevision("writer-omitted-without-recording-device", digest: "SnLRcZTmF2g6qdUj-M4UiX6yZGYMavPfLDzJ_3hQPeY", assembler: 1, healthKit: 1), GoldenRevision("writer-omitted", digest: "eJqZQLyxYaLExf9ESiJxNRcvk6pO9_9vyX3ZBlqU5OU", assembler: 1, healthKit: 2), GoldenRevision("writer-self-build-equals-revision", digest: "eqwa6qOx48BRIZuR-XapwsKmhNC5G_IaKGtHU_drvVc", assembler: 1, healthKit: 1), diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json index b974ba22a..d24dd93a8 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json @@ -2070,6 +2070,87 @@ ] }, + "writer-non-ascii-name" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:996635e7-4f75-5858-a6b1-ce4288ee9d37", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:a5FfjH2Sigim1LvOqukANOtiEWSLohCZ_PtBtQCcGYA", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:Fjb3hfsf5ncskIVQueRghK7CQfBhcnB1Ee7Ap2a_iU4" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:48f9e489-810a-5256-b517-6e7ea35ab9c8", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:j0PmEtFPWn6l8_C975Pwcs881turkSjipgLo9c8tGB0", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:1a1564b3-9404-5663-970a-165916b71e51", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:uVe4635xeGOnVD4pfA3MhF3u352OARhfBrcy36aq-7Q" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:7d0a3e3a-c01f-5006-88d4-8f12514061d2", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:PpAqqcJ4T8snqx-7w-LrqZio6q9ha4LcZPqshNPcpGw", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:e3e95a8e-fdb2-5159-a4ca-8016217a25b8", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:pTfo6KE83P5KXz34pXbpR2lWSR_yPevM5z3_d31-8s8" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:69b717de-1ee4-51d9-bb00-33f040d01c65", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:nxe71ZXjPRIRdFb7bx3fw_u9IhbvIUoGExcMXiYZTkY", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.writer" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:f7e08736-1614-5537-b879-c3ddcae94235", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, "writer-omitted" : { "entries" : [ { diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-non-ascii-name.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-non-ascii-name.json new file mode 100644 index 000000000..df7704e7e --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/writer-non-ascii-name.json @@ -0,0 +1,606 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Fjb3hfsf5ncskIVQueRghK7CQfBhcnB1Ee7Ap2a_iU4" + } + } + ], + "fullUrl" : "urn:uuid:996635e7-4f75-5858-a6b1-ce4288ee9d37", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "device" : { + "reference" : "urn:uuid:48f9e489-810a-5256-b517-6e7ea35ab9c8" + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:a5FfjH2Sigim1LvOqukANOtiEWSLohCZ_PtBtQCcGYA" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Fjb3hfsf5ncskIVQueRghK7CQfBhcnB1Ee7Ap2a_iU4" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:j0PmEtFPWn6l8_C975Pwcs881turkSjipgLo9c8tGB0" + } + } + ], + "fullUrl" : "urn:uuid:48f9e489-810a-5256-b517-6e7ea35ab9c8", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:j0PmEtFPWn6l8_C975Pwcs881turkSjipgLo9c8tGB0" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:uVe4635xeGOnVD4pfA3MhF3u352OARhfBrcy36aq-7Q" + } + } + ], + "fullUrl" : "urn:uuid:1a1564b3-9404-5663-970a-165916b71e51", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:uVe4635xeGOnVD4pfA3MhF3u352OARhfBrcy36aq-7Q" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:PpAqqcJ4T8snqx-7w-LrqZio6q9ha4LcZPqshNPcpGw" + } + } + ], + "fullUrl" : "urn:uuid:7d0a3e3a-c01f-5006-88d4-8f12514061d2", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:PpAqqcJ4T8snqx-7w-LrqZio6q9ha4LcZPqshNPcpGw" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:1a1564b3-9404-5663-970a-165916b71e51" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:pTfo6KE83P5KXz34pXbpR2lWSR_yPevM5z3_d31-8s8" + } + } + ], + "fullUrl" : "urn:uuid:e3e95a8e-fdb2-5159-a4ca-8016217a25b8", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:pTfo6KE83P5KXz34pXbpR2lWSR_yPevM5z3_d31-8s8" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "iPhone17,1", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "26.1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:nxe71ZXjPRIRdFb7bx3fw_u9IhbvIUoGExcMXiYZTkY" + } + } + ], + "fullUrl" : "urn:uuid:69b717de-1ee4-51d9-bb00-33f040d01c65", + "resource" : { + "deviceName" : [ + { + "name" : "Santé Journal", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:nxe71ZXjPRIRdFb7bx3fw_u9IhbvIUoGExcMXiYZTkY" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.example.writer" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:e3e95a8e-fdb2-5159-a4ca-8016217a25b8" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "42" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:1gjgNVAjCKLlCoHbfTsnLzsE73yGFMx62CXzbeDtnuA" + } + } + ], + "fullUrl" : "urn:uuid:f7e08736-1614-5537-b879-c3ddcae94235", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:7d0a3e3a-c01f-5006-88d4-8f12514061d2" + } + } + ], + "entity" : [ + { + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "author", + "display" : "Author", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:69b717de-1ee4-51d9-bb00-33f040d01c65" + } + } + ], + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:a5FfjH2Sigim1LvOqukANOtiEWSLohCZ_PtBtQCcGYA" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:996635e7-4f75-5858-a6b1-ce4288ee9d37" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:30" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file From e870374227e2246c76adb351af5637cc34048ee8 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 14:03:40 +0200 Subject: [PATCH 025/220] Fail Golden Regeneration Runs and Pin Every Case's Companions and Identities Fix-round step G3, audit ledger section 1 confirmed findings 5 (companion graphs, conversion identifiers and the case list are unpinned), 8 (setting GROVE_GOLDEN_OUTPUT_DIR skips the comparison and still reports success) and the fixture half of 10 (the workout golden is built from the benchmark's SampleFactory). - Regeneration fails visibly: with GROVE_GOLDEN_OUTPUT_DIR set, everyCaseIsDeterministicAndPinnable writes every case as before and then records "Regenerated N goldens into and compared none", so a run that compared nothing can no longer end in TEST SUCCEEDED. - Companions: GoldenOutput(primaryOf:companions:) requires the exact companion count of the set it takes the primary from (0 everywhere, 1 for electrocardiogram-with-symptom, whose companion has its own case). It replaces the five direct `.primary` call sites (GoldenFixtures.convert and the electrocardiogram, electrocardiogram-with-symptom, heartbeat-series and workout-route cases), which dropped any companion silently. - Identities and source: GoldenOutput keeps the conversion's ExchangeGraphIdentifiers and HealthKitSourceRecord, and matchesCheckedInGolden reads them against the graph's own tokens (reportMismatches): every reported output and Device is the entry its fullUrl names and carries that identifier, the Provenance is the one entry at its entry-node fullUrl, the source-record and artifact identities sit on the primary output, every Observation, DocumentReference and Device entry is reported (a distinct gateway application aside), and the source re-mints the graph's source-record identity through the test identity scope. The graphs are pinned by the goldens, so this pins what the API reports beside them. - Case list: already pinned by the G17 table (GoldenOutputRevisionTests, ffec7fbc), whose literal rows must equal the checked-in goldens. - The workout fixture is GoldenFixtures.workout(withEvents:), the same run written out in the fixtures, no longer read from the benchmark factory; workout-session regenerates byte-identical. GoldenCaseError.workoutNotBuilt is gone with the lookup it guarded. Mutation proof (each applied alone, full GroveHealthKitFHIRTests on macOS, then reverted; unmutated: 275 total, 273 passed, 2 skipped): - an ECG without symptoms reports itself as its own companion: fails matchesCheckedInGolden, everyCaseIsDeterministicAndPinnable and two ExchangeGraphBytesTests with unexpectedCompanions(1). The same mutation against the previous harness (tests of e2e5397f) passes all 275. - the assembler reports no childOutputs: fails matchesCheckedInGolden (electrocardiogram: ["outputs"]). - HealthKitAssembly reports every source as heart rate: fails matchesCheckedInGolden (step-count-period: ["source"]). - a regeneration run (TEST_RUNNER_GROVE_GOLDEN_OUTPUT_DIR outside the worktree) fails with the regeneration issue; with the Issue.record turned into a print it passes, which is the finding. Output diff: none. A regeneration writes all 43 goldens and outlines.json byte-identical to the checked-in files. Gates: GroveHealthKitFHIR macOS 275 total, 273 passed, 2 skipped; swiftlint --strict: no findings; reuse lint: compliant (tests only). Co-Authored-By: Claude Opus 5.5 --- .../GoldenGraphCases+Documents.swift | 9 +- .../GoldenGraphCases.swift | 2 +- .../GoldenGraphFixtures.swift | 144 ++++++++++++++++-- .../GoldenGraphTests.swift | 25 ++- .../StoredSampleFixturesTests.swift | 2 +- 5 files changed, 146 insertions(+), 36 deletions(-) diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift index b42b2dc7a..a819717bb 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift @@ -20,7 +20,6 @@ enum GoldenCaseError: Error { case unexpectedCompanions(Int) case routeOmitted case unknownTimeZone(String) - case workoutNotBuilt } @@ -33,10 +32,10 @@ extension GoldenCase { /// private storage the fixtures do not write; the envelope sample is a real `HKElectrocardiogram` nonetheless. static let documents: [GoldenCase] = [ GoldenCase("electrocardiogram", sequence: 60) { sequence in - GoldenOutput(try electrocardiogram(uuid: 60, sequence: sequence, symptom: nil).primary) + try GoldenOutput(primaryOf: electrocardiogram(uuid: 60, sequence: sequence, symptom: nil)) }, GoldenCase("electrocardiogram-with-symptom", sequence: 61) { sequence in - GoldenOutput(try electrocardiogram(uuid: 61, sequence: sequence, symptom: GoldenFixtures.uuid(0x61)).primary) + try GoldenOutput(primaryOf: electrocardiogram(uuid: 61, sequence: sequence, symptom: GoldenFixtures.uuid(0x61)), companions: 1) }, GoldenCase("electrocardiogram-symptom-companion", sequence: 61) { sequence in let companions = try electrocardiogram(uuid: 61, sequence: sequence, symptom: GoldenFixtures.uuid(0x61)).companions @@ -56,7 +55,7 @@ extension GoldenCase { HealthKitHeartbeat(timeSinceSeriesStart: 0.84, precededByGap: false), HealthKitHeartbeat(timeSinceSeriesStart: 1.71, precededByGap: true) ]) - return GoldenOutput(try HealthKitConverter().convert(record, context: GoldenFixtures.context(sequence: sequence)).primary) + return try GoldenOutput(primaryOf: HealthKitConverter().convert(record, context: GoldenFixtures.context(sequence: sequence))) }, GoldenCase("workout-route", sequence: 63) { sequence in let route = try StoredSampleFixtures.seriesSample( @@ -70,7 +69,7 @@ extension GoldenCase { guard let conversion = try HealthKitConverter().convert(record, context: GoldenFixtures.context(sequence: sequence, inputs)) else { throw GoldenCaseError.routeOmitted } - return GoldenOutput(conversion.primary) + return try GoldenOutput(primaryOf: conversion) } ] + clinicalDocuments diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift index 30827526f..3ef93a70f 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift @@ -114,7 +114,7 @@ extension GoldenCase { }, GoldenCase("workout-session", sequence: 14) { sequence in try GoldenFixtures.convert( - StoredSampleFixtures.stored(try GoldenFixtures.workout(withEvents: true), uuid: GoldenFixtures.uuid(14)), + StoredSampleFixtures.stored(GoldenFixtures.workout(withEvents: true), uuid: GoldenFixtures.uuid(14)), sequence: sequence ) } diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift index 88e8f49fe..b2053e630 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift @@ -9,21 +9,27 @@ #if canImport(HealthKit) import Foundation -import GroveFHIRContract +@testable import GroveFHIRContract @testable import GroveHealthKitFHIR import HealthKit import ModelsR4 import Testing -/// What one case pins: the graph the old API emitted and, in order, what it reported losing. +/// What one case pins: the graph the API emitted, what it reported losing, in order, and what it reported about +/// the graph's record and identities. struct GoldenOutput: Sendable { let graph: ExchangeGraph - let warnings: [HealthKitConversionWarning] - /// Each warning as the outline spells it: the registry code, then the field, device name or keys it names. - var renderedWarnings: [String] { - warnings.map { warning in + let renderedWarnings: [String] + /// The record the conversion names; `nil` for a retraction, which names its record through its targets. + let source: HealthKitSourceRecord? + /// The identities the conversion reported; `nil` where the API reports none. + let identifiers: ExchangeGraphIdentifiers? + + init(_ conversion: HealthKitConversion) { + graph = conversion.graph + renderedWarnings = conversion.warnings.map { warning in switch warning { case .recordingDeviceOmitted(let deviceName): "\(warning.diagnostic.code)(\(deviceName ?? ""))" @@ -33,16 +39,24 @@ struct GoldenOutput: Sendable { "\(warning.diagnostic.code)(\(keys.joined(separator: ",")))" } } - } - - init(_ conversion: HealthKitConversion) { - graph = conversion.graph - warnings = conversion.warnings + source = conversion.source + identifiers = conversion.identifiers } init(_ retraction: RetractionEvent) { graph = retraction.graph - warnings = [] + renderedWarnings = [] + source = nil + identifiers = nil + } + + /// The primary graph of `set`, which must carry exactly `companions` companion graphs: a case that pins only + /// the primary would otherwise let a spurious or a lost companion pass. + init(primaryOf set: HealthKitConversionSet, companions: Int = 0) throws { + guard set.companions.count == companions else { + throw GoldenCaseError.unexpectedCompanions(set.companions.count) + } + self.init(set.primary) } } @@ -165,9 +179,9 @@ enum GoldenFixtures { ) } - /// The primary graph of `sample` under the old public entry point, with what the conversion reported losing. + /// The one graph of `sample` under the old public entry point, with what the conversion reported losing. static func convert(_ sample: HKSample, sequence: UInt64, _ inputs: Inputs = Inputs()) throws -> GoldenOutput { - GoldenOutput(try HealthKitConverter().convert(sample, context: context(sequence: sequence, inputs)).primary) + try GoldenOutput(primaryOf: HealthKitConverter().convert(sample, context: context(sequence: sequence, inputs))) } /// A 72 bpm heart rate; `end` stays the start instant unless a case states an interval. @@ -231,6 +245,38 @@ enum GoldenFixtures { ApplicationDevice.test(name: "Grove Test", bundleIdentifier: ApplicationDevice.test.bundleIdentifier, version: version, build: build) } + /// A one-hour run in Berlin with 640 kcal and 10 km; with events, a pause, a resume, eight laps and two + /// segments, which the converter withholds. + static func workout(withEvents: Bool) -> HKWorkout { + let begin = Date(timeIntervalSince1970: 1_786_000_000) + var events: [HKWorkoutEvent] = [] + if withEvents { + events = [ + HKWorkoutEvent(type: .pause, dateInterval: DateInterval(start: begin.addingTimeInterval(600), duration: 0), metadata: nil), + HKWorkoutEvent(type: .resume, dateInterval: DateInterval(start: begin.addingTimeInterval(660), duration: 0), metadata: nil) + ] + events += (0..<8).map { lap in + HKWorkoutEvent(type: .lap, dateInterval: DateInterval(start: begin.addingTimeInterval(Double(lap) * 400), duration: 400), metadata: nil) + } + events += (0..<2).map { segment in + HKWorkoutEvent( + type: .segment, + dateInterval: DateInterval(start: begin.addingTimeInterval(Double(segment) * 1_800), duration: 1_800), + metadata: nil + ) + } + } + return HKWorkout( + activityType: .running, + start: begin, + end: begin.addingTimeInterval(3_600), + workoutEvents: events.isEmpty ? nil : events, + totalEnergyBurned: HKQuantity(unit: .kilocalorie(), doubleValue: 640), + totalDistance: HKQuantity(unit: .meter(), doubleValue: 10_000), + metadata: [HKMetadataKeyTimeZone: "Europe/Berlin"] + ) + } + /// The sample's writer when the converter wrote it: the converter's bundle identifier, stating `revisionVersion`. static func selfWriter(revisionVersion: String?) -> StoredSampleFixtures.Writer { StoredSampleFixtures.Writer( @@ -242,4 +288,74 @@ enum GoldenFixtures { } } + +extension GoldenOutput { + /// Where what the conversion reported disagrees with the graph it reported it for, read from the graph's own + /// tokens: each reported output and Device is the entry its fullUrl names and carries that identity, the + /// Provenance is the one entry at its entry-node fullUrl, the source record and artifact identities are on the + /// primary output, every output and Device entry is reported (a distinct gateway application aside, which no + /// identity names), and the source is the record the graph's source identity is minted from. Empty for a + /// retraction, which reports neither. + func reportMismatches(identityScope: OpaqueIdentityScope, repositoryScope: BusinessIdentifier) throws -> [String] { + guard let identifiers, let source else { + return [] + } + let entries: [LosslessJSONValue] = try LosslessJSONValue(parsing: graph.json)["entry"]?.elements ?? [] + var byURL: [String: LosslessJSONValue] = [:] + for entry in entries { + byURL[entry["fullUrl"]?.text ?? ""] = entry + } + func carries(_ url: String, _ identity: RoledIdentifier?) -> Bool { + guard let identity else { + return true + } + let stated: [LosslessJSONValue] = byURL[url]?["resource"]?["identifier"]?.elements ?? [] + return stated.contains { $0["system"]?.text == identity.identifier.system.rawValue && $0["value"]?.text == identity.identifier.value } + } + func urls(ofTypes types: Set) -> Set { + Set(entries.filter { types.contains($0["resource"]?["resourceType"]?.text ?? "") }.compactMap { $0["fullUrl"]?.text }) + } + let optionalDevices: [RoledIdentifier] = [ + identifiers.recordingDeviceSnapshot, identifiers.writerSnapshot, identifiers.writerHostSnapshot + ].compactMap(\.self) + let devices: [RoledIdentifier] = [identifiers.applicationSnapshot, identifiers.hostSnapshot] + optionalDevices + let outputs: [RoledIdentifier] = [identifiers.primaryOutput] + identifiers.childOutputs + var mismatches: [String] = [] + for node in outputs + devices where !carries(try node.fullURLString, node) { + mismatches.append("node \(node.identifier.value)") + } + // A Provenance carries no identifier; its entry-node key is its fullUrl. + if urls(ofTypes: ["Provenance"]) != [try identifiers.provenance.fullURLString] { + mismatches.append("provenance") + } + let primaryURL = try identifiers.primaryOutput.fullURLString + if identifiers.event != graph.eventIdentifier.identifier { + mismatches.append("event") + } + if !carries(primaryURL, identifiers.sourceRecord) || !carries(primaryURL, identifiers.sourceArtifact) { + mismatches.append("source record or artifact identity") + } + if urls(ofTypes: ["Observation", "DocumentReference"]) != Set(try outputs.map { try $0.fullURLString }) { + mismatches.append("outputs") + } + let deviceURLs = Set(try devices.map { try $0.fullURLString }) + let extensions: [LosslessJSONValue] = entries.flatMap { $0["resource"]?["extension"]?.elements ?? [] } + let gatewayURLs = Set(extensions.filter { $0["url"]?.text == Canonicals.gatewayDevice.value?.url.absoluteString } + .compactMap { $0["valueReference"]?["reference"]?.text }) + if urls(ofTypes: ["Device"]).subtracting(gatewayURLs.subtracting(deviceURLs)) != deviceURLs { + mismatches.append("devices") + } + let minted = try identityScope.sourceRecord( + adapterID: HealthKitConverter.adapterID, + sourceType: source.type.rawValue, + repositoryScope: repositoryScope, + nativeRecordID: source.uuid.uuidString.lowercased() + ) + if minted.identifier != identifiers.sourceRecord { + mismatches.append("source") + } + return mismatches + } +} + #endif diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift index 0e5a42bed..f07a262d9 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift @@ -21,7 +21,8 @@ import Testing /// Goldens are regenerated OUTSIDE the checkout: `GROVE_GOLDEN_OUTPUT_DIR` (under `xcodebuild`, pass it as /// `TEST_RUNNER_GROVE_GOLDEN_OUTPUT_DIR`) names a directory the suite writes every case into, and the files are /// copied into `Resources/Goldens/` afterwards. Writing into the checkout while Xcode runs the tests makes it -/// re-resolve the package graph mid-run. +/// re-resolve the package graph mid-run. A regeneration run compares nothing, so it fails on purpose: it can +/// never be mistaken for a green golden run. enum GoldenStore { struct MissingGolden: Error, CustomStringConvertible { let name: String @@ -170,6 +171,9 @@ struct GoldenGraphTests { GoldenOutline(expected, warnings: outline.warnings) == outline, "\(goldenCase.name): outlines.json does not describe the checked-in golden" ) + let scope = ExchangeEventContext.test() + let mismatches = try output.reportMismatches(identityScope: scope.identityScope, repositoryScope: scope.repositoryScope) + #expect(mismatches.isEmpty, "\(goldenCase.name) reports what its graph does not carry: \(mismatches)") if let difference = TokenDiff.firstDifference(expected: expected, actual: actual) { Issue.record("\(goldenCase.name) drifted from its golden at \(difference)") } @@ -190,7 +194,8 @@ struct GoldenGraphTests { /// Every case is named once, mints its own event, converts to the same tokens and warnings twice in one process, /// and re-encodes with sorted members to the same tokens as its wire bytes. With `GROVE_GOLDEN_OUTPUT_DIR` set, - /// this is also the regeneration: each case's sorted-member JSON and the outlines are written there. + /// this is also the regeneration: each case's sorted-member JSON and the outlines are written there, and the run + /// fails, as it compared nothing. @Test func everyCaseIsDeterministicAndPinnable() throws { var outlines: [String: GoldenOutline] = [:] @@ -201,7 +206,7 @@ struct GoldenGraphTests { let wire = try LosslessJSONValue(parsing: graph.json) let again = try goldenCase.output() #expect(try LosslessJSONValue(parsing: again.graph.json) == wire, "\(goldenCase.name) is not deterministic") - #expect(again.warnings == output.warnings, "\(goldenCase.name) does not warn deterministically") + #expect(again.renderedWarnings == output.renderedWarnings, "\(goldenCase.name) does not warn deterministically") let sorted = try GoldenStore.encoder.encode(graph.bundle) #expect(try LosslessJSONValue(parsing: sorted) == wire, "\(goldenCase.name): a sorted re-encode changes the tokens") @@ -217,6 +222,7 @@ struct GoldenGraphTests { } if let directory = GoldenStore.outputDirectory { try GoldenStore.encoder.encode(outlines).write(to: directory.appendingPathComponent("\(GoldenStore.outlinesName).json")) + Issue.record("Regenerated \(outlines.count) goldens into \(directory.path) and compared none: copy them into Resources/Goldens and rerun") } } @@ -225,7 +231,7 @@ struct GoldenGraphTests { /// does not admit.) @Test(arguments: [false, true]) func workoutsExportTheSessionAlone(withEvents: Bool) throws { - let workout = try StoredSampleFixtures.stored(try GoldenFixtures.workout(withEvents: withEvents), uuid: GoldenFixtures.uuid(0xA0)) + let workout = try StoredSampleFixtures.stored(GoldenFixtures.workout(withEvents: withEvents), uuid: GoldenFixtures.uuid(0xA0)) let context = try GoldenFixtures.context(sequence: 200) let conversion = try HealthKitConverter().convert(workout, context: context) let observations = conversion.bundle.entry?.compactMap { $0.resource?.get(if: Observation.self) } ?? [] @@ -329,15 +335,4 @@ extension GoldenCase { } -extension GoldenFixtures { - /// The benchmark's one-hour run: with events, a pause and resume, eight laps and two segments, which the old - /// converter turns into twelve segment children before refusing the graph. - static func workout(withEvents: Bool) throws -> HKWorkout { - guard let workout = SampleFactory.workouts(count: 1, withEvents: withEvents).first as? HKWorkout else { - throw GoldenCaseError.workoutNotBuilt - } - return workout - } -} - #endif diff --git a/Tests/GroveHealthKitFHIRTests/StoredSampleFixturesTests.swift b/Tests/GroveHealthKitFHIRTests/StoredSampleFixturesTests.swift index 025c36832..16e84ad8f 100644 --- a/Tests/GroveHealthKitFHIRTests/StoredSampleFixturesTests.swift +++ b/Tests/GroveHealthKitFHIRTests/StoredSampleFixturesTests.swift @@ -64,7 +64,7 @@ struct StoredSampleFixturesTests { let correlation = try GoldenCase.bloodPressure() #expect(correlation.uuid == GoldenFixtures.uuid(9)) #expect(correlation.objects.map(\.uuid).sorted { $0.uuidString < $1.uuidString } == [GoldenFixtures.uuid(0x91), GoldenFixtures.uuid(0x92)]) - let workout = try StoredSampleFixtures.stored(try GoldenFixtures.workout(withEvents: true), uuid: Self.uuid, writer: Self.writer) + let workout = try StoredSampleFixtures.stored(GoldenFixtures.workout(withEvents: true), uuid: Self.uuid, writer: Self.writer) try Self.expectStored(workout) #expect(workout.workoutEvents?.count == 12) } From 9b2e2d54bb10a4406a53a699ac1efaa982a6aa58 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 14:13:49 +0200 Subject: [PATCH 026/220] Pin the Exporter's Own Graphs in Goldens Under Default and Deployment Options Fix-round step G3, audit ledger section 1 confirmed findings 2 (no golden runs through HealthKitFHIRExporter or MHC's options), 3 (HKClinicalRecord glue unpinned), 4 (envelope options combined only with heart rate), the exporter half of 5 (the exporter delivers every graph of a set) and survivor M5 of finding 1 (effective time truncated to whole seconds); G2 leftover: no golden had an Apple per-device (com.apple.health.) source. Every golden so far came from the deprecated converter, so the exporter's own layer (frozen facts and studies in the envelope, the options, the legacy Bundle.id, the gateway role for own writes, the ECG companion delivery, the retraction path, the clinical-record glue) was pinned nowhere in bytes. New golden group "exporter" (sequences 100-119, GoldenGraphCases+Exporter .swift): each case exports through a fresh in-memory ledger whose producer entry hands out the case's sequence next under the fixed producer instance of every golden, at the golden conversion instant, so the events are as reproducible as the converter's. GoldenOutput gains init(_ export:), which records the export's source and its diagnostics as code@location. - exporter-default-apple-watch-heart-rate: Options() on a heart rate whose source is com.apple.health. ("Lukas's Apple Watch") and whose HKDevice names its unit: no writer, no author, the recording Device only (W1 in bytes). - The deployment lane uses options equal to MyHeartCounts' Options.myHeartCounts (HealthKitGroveConversion.swift:45-51 at MHC 79d70dbf) under G2's writer policy: nativeIdentifier .authorized under the deployment's own system, legacyBundleID .healthKitUUID, role .gatewayForOwnWrites, writer .applications([own bundle id]), every other option at its default; the producer states an application with a build and one study enrollment, as MHC's does: - exporter-deployment-own-heart-rate: the deployment's own write in the running build, starting at a sub-second instant: gateway extension, classified writer and writer host, disclosed UUID, Bundle.id, study links. - exporter-deployment-electrocardiogram and ...-symptom: one export call of an ECG with a correlated symptom through the evidence seam; the call must deliver exactly these two graphs, the ECG's average-heart-rate child and the symptom companion each carrying the study link. - exporter-deployment-blood-pressure, exporter-deployment-state-of-mind: study links on a correlation and on state of mind. - exporter-deployment-retraction: a heart-rate deletion with sub-second bounds through retract: Bundle.id, the period at millisecond precision. - exporter-clinical-record-r4 / -dstu2: an HKClinicalRecord per admitted release through export(_:), built by the new StoredSampleFixtures.clinicalRecord (KVC on HKClinicalRecord and HKFHIRResource, read back or fail), pinning convertClinicalRecord's glue. watchOS has no clinical records; both are in GoldenCase.unavailableHere there. GoldenCase.bloodPressure takes its ordinals (defaults unchanged). G17 rows: the 9 new goldens at assembler 1, healthKit 2 (current), no bump; outlines.json row updated (it only gains the 9 entries; all existing outlines unchanged). Mutation proof (each applied alone, full GroveHealthKitFHIRTests on macOS, then reverted; unmutated: 275 total, 273 passed, 2 skipped): - audit M5, effective start truncated to whole seconds: fails matchesCheckedInGolden for exporter-deployment-own-heart-rate at $.entry[0].resource.effectiveDateTime (golden ...:00.512-07:00). Survived the whole suite before this commit. - the ECG average-heart-rate child without the studies link: fails exporter-deployment-electrocardiogram (outline). - the exporter builds every graph with no studies: fails exporter-deployment-own-heart-rate (outline). - legacy Bundle.id lowercased: fails exporter-deployment-own-heart-rate at $.id, plus policiesApply and retractionBoundsAndLedger. - convertClinicalRecord ignores the resource's release (always R4): fails exporter-clinical-record-dstu2 at ...attachment.contentType. Output diff: none; the 43 existing goldens and their outlines regenerate byte-identical. Gates: GroveHealthKitFHIR macOS 275 total, 273 passed, 2 skipped; swiftlint --strict: no findings; reuse lint: compliant (tests only). Co-Authored-By: Claude Opus 5.5 --- .../GoldenGraphCases+Documents.swift | 1 + .../GoldenGraphCases+Exporter.swift | 208 +++++ .../GoldenGraphCases.swift | 12 +- .../GoldenGraphFixtures.swift | 7 + .../GoldenGraphTests.swift | 2 +- .../GoldenOutputRevisionTests.swift | 11 +- .../exporter-clinical-record-dstu2.json | 459 +++++++++++ .../Goldens/exporter-clinical-record-r4.json | 459 +++++++++++ ...porter-default-apple-watch-heart-rate.json | 454 +++++++++++ .../exporter-deployment-blood-pressure.json | 607 ++++++++++++++ ...-deployment-electrocardiogram-symptom.json | 586 ++++++++++++++ ...exporter-deployment-electrocardiogram.json | 744 ++++++++++++++++++ .../exporter-deployment-own-heart-rate.json | 737 +++++++++++++++++ .../exporter-deployment-retraction.json | 144 ++++ .../exporter-deployment-state-of-mind.json | 548 +++++++++++++ .../Resources/Goldens/outlines.json | 684 ++++++++++++++++ .../StoredSampleFixtures.swift | 37 + 17 files changed, 5694 insertions(+), 6 deletions(-) create mode 100644 Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Exporter.swift create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-clinical-record-dstu2.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-clinical-record-r4.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-default-apple-watch-heart-rate.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-blood-pressure.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-electrocardiogram-symptom.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-electrocardiogram.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-own-heart-rate.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-retraction.json create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-state-of-mind.json diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift index a819717bb..c7d517572 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift @@ -20,6 +20,7 @@ enum GoldenCaseError: Error { case unexpectedCompanions(Int) case routeOmitted case unknownTimeZone(String) + case notExported(String) } diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Exporter.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Exporter.swift new file mode 100644 index 000000000..6de2ff418 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Exporter.swift @@ -0,0 +1,208 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +@testable import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit +import ModelsR4 + + +/// The exporter configurations and records the exporter goldens use. +enum ExporterGolden { + /// The deployment's own application, in the build it runs. + static let deploymentApplication = ApplicationDevice.test(name: "Grove Study", bundleIdentifier: "org.example.study", version: "4.1.0", build: "412") + static let deploymentStudies: [StudyEnrollment] = [.test("study-a")] + + /// A sample the deployment's own application wrote in the build it runs. + static let deploymentWriter = StoredSampleFixtures.Writer( + name: deploymentApplication.name, + bundleIdentifier: deploymentApplication.bundleIdentifier, + version: deploymentApplication.build, + productType: "iPhone17,1" + ) + + /// An Apple per-device source: the watch that recorded the sample, as HealthKit names it. + static let watchSource = StoredSampleFixtures.Writer( + name: "Lukas's Apple Watch", + bundleIdentifier: "com.apple.health.6C4B1D1E-0000-4000-8000-0000000000B0", + version: "26.1", + productType: "Watch7,12" + ) + + /// Options equal to MyHeartCounts' `Options.myHeartCounts` (`HealthKitGroveConversion.swift`, MyHeartCounts + /// 79d70dbf) under the fix round's writer policy: the HealthKit UUID disclosed under the deployment's own system + /// and kept as `Bundle.id`, the deployment's own writes mediated by it in the build that wrote them, its own + /// bundle identifier the one source classified as an application, and every other option at its default. + static var deploymentOptions: HealthKitFHIRExporter.Options { + var options = HealthKitFHIRExporter.Options() + options.nativeIdentifier = .authorized(system: GoldenFixtures.nativeIdentifierSystem) + options.legacyBundleID = .healthKitUUID + options.role = .gatewayForOwnWrites + options.writer = .applications([deploymentApplication.bundleIdentifier]) + return options + } + + /// An exporter whose fresh ledger hands out `sequence` next under the fixed producer instance, with the + /// deployment's application, studies and options, or with the test application and default options. + static func exporter(sequence: UInt64, deployment: Bool) throws -> HealthKitFHIRExporter { + let storage = ExchangeEventSequencer.InMemoryStorage() + let instance = ExchangeEventContext.test().event.producerInstance + try storage.transaction { try $0.write(ProducerEntry(instance: instance, next: sequence).encoded(), for: LedgerKey.producer) } + let producer = try ExporterFixtures.producer( + application: deployment ? deploymentApplication : .test, + studies: deployment ? deploymentStudies : [], + sequencer: ExchangeEventSequencer(storage: storage) + ) + return try ExporterFixtures.exporter(producer) { options in + if deployment { + options = deploymentOptions + } + } + } + + /// The graph at `index` of the `count` exports one call delivers for `inputs`, in delivery order. + static func output( + of inputs: [HealthKitFHIRExporter.Input], + sequence: UInt64, + deployment: Bool, + index: Int = 0, + of count: Int = 1 + ) throws -> GoldenOutput { + let (exports, _) = try ExporterFixtures.collect(exporter(sequence: sequence, deployment: deployment), inputs) + guard exports.count == count else { + throw GoldenCaseError.unexpectedCompanions(exports.count - 1) + } + return try GoldenOutput(exports[index]) + } + + /// The one export of a call. + static func single(_ exports: [HealthKitFHIRExporter.Export]) throws -> HealthKitFHIRExporter.Export { + guard exports.count == 1, let export = exports.first else { + throw GoldenCaseError.unexpectedCompanions(exports.count - 1) + } + return export + } + + /// The sinus-rhythm ECG with one correlated symptom, through the exporter's evidence seam. + static func electrocardiogram() throws -> HealthKitFHIRExporter.Input { + try ExporterFixtures.electrocardiogram(uuid: 0xB2, symptoms: [GoldenCase.symptom(uuid: GoldenFixtures.uuid(0xB3))]) + } + + #if !os(watchOS) + /// A lab result the provider issued in `version`, carried byte for byte. + static func clinicalRecord(uuid ordinal: UInt8, version: HKFHIRVersion, payload: String) throws -> HKClinicalRecord { + try StoredSampleFixtures.clinicalRecord( + .labResultRecord, + shape: GoldenCase.seriesShape(uuid: ordinal, duration: 0), + displayName: "Hemoglobin A1c", + resource: StoredSampleFixtures.ClinicalResource(version: version, type: .observation, identifier: "a1c", data: Data(payload.utf8)) + ) + } + #endif +} + + +/// The graphs `HealthKitFHIRExporter` itself delivers: its ledger, its options and the facts frozen with each +/// reservation, which the converter's goldens never reach. +extension GoldenCase { + /// Sequences 100-119. Each case exports through a fresh ledger that hands out its sequence next under the fixed + /// producer instance every golden states, so an exporter golden is as reproducible as a converter golden. + static let exporter: [GoldenCase] = [ + // The exporter's defaults on an Apple per-device source: no writer and no author, and a recording Device + // only because the sample's HKDevice names its unit. + GoldenCase("exporter-default-apple-watch-heart-rate", sequence: 100) { sequence in + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0xB0), device: GoldenFixtures.watch, writer: ExporterGolden.watchSource) + return try ExporterGolden.output(of: [.record(.sample(sample))], sequence: sequence, deployment: false) + }, + // The deployment's own write in the build that runs, starting at a sub-second instant: its gateway role, + // its classified writer, the disclosed UUID, the legacy Bundle.id and the study context. + GoldenCase("exporter-deployment-own-heart-rate", sequence: 101) { sequence in + let start = GoldenFixtures.sampleStart.addingTimeInterval(0.512) + let heartRate = HKQuantitySample( + type: HKQuantityType(.heartRate), + quantity: HKQuantity(unit: GoldenFixtures.beatsPerMinute, doubleValue: 64), + start: start, + end: start, + device: GoldenFixtures.watch, + metadata: GoldenFixtures.timeZoneMetadata + ) + let sample = try StoredSampleFixtures.stored(heartRate, uuid: GoldenFixtures.uuid(0xB1), writer: ExporterGolden.deploymentWriter) + return try ExporterGolden.output(of: [.record(.sample(sample))], sequence: sequence, deployment: true) + }, + GoldenCase("exporter-deployment-electrocardiogram", sequence: 102) { sequence in + try ExporterGolden.output(of: [ExporterGolden.electrocardiogram()], sequence: sequence, deployment: true, index: 0, of: 2) + }, + GoldenCase("exporter-deployment-electrocardiogram-symptom", sequence: 102) { sequence in + try ExporterGolden.output(of: [ExporterGolden.electrocardiogram()], sequence: sequence, deployment: true, index: 1, of: 2) + }, + GoldenCase("exporter-deployment-blood-pressure", sequence: 104) { sequence in + let correlation = try bloodPressure(uuid: 0xB4, components: (0xB5, 0xB6)) + return try ExporterGolden.output(of: [.record(.sample(correlation))], sequence: sequence, deployment: true) + }, + GoldenCase("exporter-deployment-state-of-mind", sequence: 105) { sequence in + let stateOfMind = HKStateOfMind( + date: GoldenFixtures.sampleStart, + kind: .dailyMood, + valence: -0.25, + labels: [.stressed], + associations: [.health], + metadata: GoldenFixtures.timeZoneMetadata + ) + let sample = try StoredSampleFixtures.stored(stateOfMind, uuid: GoldenFixtures.uuid(0xB7)) + return try ExporterGolden.output(of: [.record(.sample(sample))], sequence: sequence, deployment: true) + }, + // A deletion noted between two queries, both stated at sub-second precision. + GoldenCase("exporter-deployment-retraction", sequence: 106) { sequence in + let deletion = HealthKitFHIRExporter.Deletion( + uuid: GoldenFixtures.uuid(0xB8), + sourceType: .heartRate, + deletedAfter: GoldenFixtures.sampleStart.addingTimeInterval(0.125), + detectedAt: GoldenFixtures.conversionInstant.addingTimeInterval(-0.25) + ) + let (exports, _) = try ExporterFixtures.retract(ExporterGolden.exporter(sequence: sequence, deployment: true), [deletion]) + return try GoldenOutput(ExporterGolden.single(exports)) + } + ] + exporterClinicalRecords + + #if os(watchOS) + static let exporterClinicalRecords: [GoldenCase] = [] + #else + /// `HKClinicalRecord` has no initializer; the stored-sample fixtures build one per release the guide admits. + static let exporterClinicalRecords: [GoldenCase] = [ + GoldenCase("exporter-clinical-record-r4", sequence: 107) { sequence in + let record = try ExporterGolden.clinicalRecord(uuid: 0xB9, version: .primaryR4(), payload: #"{"resourceType":"Observation","id":"a1c-r4","status":"final"}"#) + return try ExporterGolden.output(of: [.record(.sample(record))], sequence: sequence, deployment: false) + }, + GoldenCase("exporter-clinical-record-dstu2", sequence: 108) { sequence in + let record = try ExporterGolden.clinicalRecord(uuid: 0xBA, version: .primaryDSTU2(), payload: #"{"resourceType":"Observation","id":"a1c-dstu2","status":"final"}"#) + return try ExporterGolden.output(of: [.record(.sample(record))], sequence: sequence, deployment: false) + } + ] + #endif +} + + +extension GoldenOutput { + /// What one export delivered: its graph and, as the outline spells them, the diagnostics it reported. + init(_ export: HealthKitFHIRExporter.Export) throws { + guard let graph = export.graph else { + throw GoldenCaseError.notExported(String(describing: export.outcome)) + } + self.init( + graph: graph, + renderedWarnings: export.warnings.map { "\($0.code)@\($0.location)" }, + source: export.source.sourceType.map { HealthKitSourceRecord(uuid: export.source.uuid, type: $0) }, + identifiers: nil + ) + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift index 3ef93a70f..0b5a0ed8c 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift @@ -18,7 +18,7 @@ import ModelsR4 /// The Observation-graph shapes the goldens pin: one sample each, converted through `HealthKitConverter.convert(_:context:)`. extension GoldenCase { /// Every pinned shape, in the order the goldens directory lists them. - static let all: [GoldenCase] = observations + writers + disclosures + documents + retractions + static let all: [GoldenCase] = observations + writers + disclosures + documents + retractions + exporter /// Sequences 1-19: the measurement shapes under the default context. static let observations: [GoldenCase] = [ @@ -250,7 +250,8 @@ extension GoldenCase { try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(ordinal), device: GoldenFixtures.watch, metadata: metadata, writer: writer) } - static func bloodPressure() throws -> HKCorrelation { + /// A 120/80 reading from the watch; the correlation and its two components each take one of the ordinals. + static func bloodPressure(uuid ordinal: UInt8 = 9, components: (systolic: UInt8, diastolic: UInt8) = (0x91, 0x92)) throws -> HKCorrelation { func component(_ type: HKQuantityTypeIdentifier, _ value: Double, uuid: UInt8) throws -> HKQuantitySample { try GoldenFixtures.quantity(type, HKQuantity(unit: .millimeterOfMercury(), doubleValue: value), uuid: GoldenFixtures.uuid(uuid), device: GoldenFixtures.watch) } @@ -258,11 +259,14 @@ extension GoldenCase { type: HKCorrelationType(.bloodPressure), start: GoldenFixtures.sampleStart, end: GoldenFixtures.sampleStart, - objects: [try component(.bloodPressureSystolic, 120, uuid: 0x91), try component(.bloodPressureDiastolic, 80, uuid: 0x92)], + objects: [ + try component(.bloodPressureSystolic, 120, uuid: components.systolic), + try component(.bloodPressureDiastolic, 80, uuid: components.diastolic) + ], device: GoldenFixtures.watch, metadata: GoldenFixtures.timeZoneMetadata ) - return try StoredSampleFixtures.stored(correlation, uuid: GoldenFixtures.uuid(9)) + return try StoredSampleFixtures.stored(correlation, uuid: GoldenFixtures.uuid(ordinal)) } } diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift index b2053e630..d09dfb7f6 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift @@ -27,6 +27,13 @@ struct GoldenOutput: Sendable { /// The identities the conversion reported; `nil` where the API reports none. let identifiers: ExchangeGraphIdentifiers? + init(graph: ExchangeGraph, renderedWarnings: [String], source: HealthKitSourceRecord?, identifiers: ExchangeGraphIdentifiers?) { + self.graph = graph + self.renderedWarnings = renderedWarnings + self.source = source + self.identifiers = identifiers + } + init(_ conversion: HealthKitConversion) { graph = conversion.graph renderedWarnings = conversion.warnings.map { warning in diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift index f07a262d9..369ae9899 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift @@ -327,7 +327,7 @@ extension GoldenCase { /// Goldens generated on macOS for cases this platform cannot build. static var unavailableHere: Set { #if os(watchOS) - ["clinical-document"] + ["clinical-document", "exporter-clinical-record-r4", "exporter-clinical-record-dstu2"] #else [] #endif diff --git a/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift b/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift index 5f652bc71..13af68bea 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift @@ -51,6 +51,15 @@ struct GoldenOutputRevisionTests { GoldenRevision("electrocardiogram-symptom-companion", digest: "EHYE0r3jfMVT2I5fBcnIQaiHnW0oaV_mZh3V12xCWDI", assembler: 1, healthKit: 2), GoldenRevision("electrocardiogram-with-symptom", digest: "oUCBD9zurrtjI0O-DbOxhf1Uo_QVwWYGQTt8HloMz9M", assembler: 1, healthKit: 2), GoldenRevision("electrocardiogram", digest: "qs8pgYDPAUqNBwnZaUsd3cKARQ-tuJWip2AexfWbMgA", assembler: 1, healthKit: 2), + GoldenRevision("exporter-clinical-record-dstu2", digest: "9U3i57-PMHal6ADvTYRUUuffIO_5pDB2kB20U_nzX1g", assembler: 1, healthKit: 2), + GoldenRevision("exporter-clinical-record-r4", digest: "fLwKd9npbWfEncV49t-W0T8TUVGFh5pjZaHMVZfv7kg", assembler: 1, healthKit: 2), + GoldenRevision("exporter-default-apple-watch-heart-rate", digest: "InGqi5S9GIR-Xqk9CltCUCExrkoBf4tOnBJguLfbVUk", assembler: 1, healthKit: 2), + GoldenRevision("exporter-deployment-blood-pressure", digest: "4rj5hMKeT-anu8BUghWFNOjRoifJo9cRyM7e4HQjl5k", assembler: 1, healthKit: 2), + GoldenRevision("exporter-deployment-electrocardiogram", digest: "fgz_sJLYrq34lVEFTVH4VlD1CyCtn0KELtFnoqlxYCw", assembler: 1, healthKit: 2), + GoldenRevision("exporter-deployment-electrocardiogram-symptom", digest: "uAPam_vM-x6yIOufY56CvWiydx6EdDJ-n7yVjZAE1kM", assembler: 1, healthKit: 2), + GoldenRevision("exporter-deployment-own-heart-rate", digest: "lJKVrYY2oi58qD26E7Z__PClm6845IZNkkcqeiEj3Z4", assembler: 1, healthKit: 2), + GoldenRevision("exporter-deployment-retraction", digest: "Cc_UaCTn-Mo0fTPXqL9sLghqSmfjEUFHr7vwCOvM55o", assembler: 1, healthKit: 2), + GoldenRevision("exporter-deployment-state-of-mind", digest: "u0OjTBrTx1KQ6gHHOWmBDmgBkzKeCAWaijDQ0Aqccno", assembler: 1, healthKit: 2), GoldenRevision("gateway-application-role", digest: "z4GLZX9z_-CYLMxzF6l78eLQXXDu_vCV6gHzIRVouYY", assembler: 1, healthKit: 2), GoldenRevision("gateway-role", digest: "6cz0Bpd-k9mt_HFFY8xyRT3dkjpDMjI8WnqlyMlGgO8", assembler: 1, healthKit: 2), GoldenRevision("heart-rate-device-without-unit-token", digest: "gKIE0MA3n8uoEIiPTWI-TJOBDAD1osZVz6C0sWLibk8", assembler: 1, healthKit: 1), @@ -63,7 +72,7 @@ struct GoldenOutputRevisionTests { GoldenRevision("heartbeat-series", digest: "fB3bdqSnBH2vJxBfzQQDFFeItPoT6Bs8Yom7uFbYS98", assembler: 1, healthKit: 2), GoldenRevision("insulin-delivery-bolus", digest: "fCw3-HgNHCW_r1bQ8bY5WiGz52iekzNbJ0-AKZp59yc", assembler: 1, healthKit: 1), GoldenRevision("native-identifier-disclosure", digest: "d0cEPkdGfs7W8CYbUpS-GDKoc64jN21WjgkWSibIAAM", assembler: 1, healthKit: 2), - GoldenRevision("outlines", digest: "IPbl39VRExwMgTppEfppx3HSBanBbsFRLVGsWo6wmxk", assembler: 1, healthKit: 2), + GoldenRevision("outlines", digest: "8v5brDMbczGBPTCqVDSNiKrYocHE3iBFv1A1APzYDAk", assembler: 1, healthKit: 2), GoldenRevision("repository-ids-on-every-node", digest: "wnO8sPt82cYYd4m50n4tycbEXWdgvNRlKjQItQI6n4Y", assembler: 1, healthKit: 1), GoldenRevision("retraction-blood-pressure", digest: "x4muVgyjqh8AfgVGhaS55MeMVmxJ58UR0hsghhedkEA", assembler: 1, healthKit: 1), GoldenRevision("retraction-electrocardiogram", digest: "JJIp4J2S4Vr0CX-d1fi3IqAmyNzuzSz4fyrF-gbrkgM", assembler: 1, healthKit: 1), diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-clinical-record-dstu2.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-clinical-record-dstu2.json new file mode 100644 index 000000000..e583c78c6 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-clinical-record-dstu2.json @@ -0,0 +1,459 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:wvo023yNyjR7BIhh_qtuM14UFTeC7ZMjdsu-ibC2fq4" + } + } + ], + "fullUrl" : "urn:uuid:8a294dd6-c351-54b4-87aa-81ea07206c74", + "resource" : { + "author" : [ + { + "reference" : "urn:uuid:d877d103-d777-5daf-b873-772c75e77e36" + }, + { + "reference" : "urn:uuid:8db0d3c9-4daf-5590-9e96-25a7f5543178" + } + ], + "content" : [ + { + "attachment" : { + "contentType" : "application/fhir+json; fhirVersion=1.0", + "data" : "eyJyZXNvdXJjZVR5cGUiOiJPYnNlcnZhdGlvbiIsImlkIjoiYTFjLWRzdHUyIiwic3RhdHVzIjoiZmluYWwifQ==", + "hash" : "wdRVh2mUjlNmiuG6UcIc4d+uLAU=", + "size" : 64, + "title" : "Lab Result Record" + }, + "format" : { + "code" : "fhir-resource", + "system" : "https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format" + } + } + ], + "date" : "2026-08-17T23:30:00Z", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKClinicalTypeIdentifierLabResultRecord" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:n7olNQTu9n8ejH_8Ri89RIeYCdubpvhza11Dem-Bp1g" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:wvo023yNyjR7BIhh_qtuM14UFTeC7ZMjdsu-ibC2fq4" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1", + "type" : { + "coding" : [ + { + "code" : "source-artifact", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:8rDEE7xtphneUrfgNiC_HhpPvozXPYQGtURrEi2Wv6w" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-clinical-record-document" + ] + }, + "resourceType" : "DocumentReference", + "status" : "current", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "type" : { + "coding" : [ + { + "code" : "lab-result-record", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-clinical-record-type" + } + ] + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:MsCECHvfM6JqFvbWOA4zwLJukhZ-qjAPd-zmwG-86pA" + } + } + ], + "fullUrl" : "urn:uuid:d877d103-d777-5daf-b873-772c75e77e36", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:MsCECHvfM6JqFvbWOA4zwLJukhZ-qjAPd-zmwG-86pA" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:dD1XvJhxxWW6z_CVc2xeBDPK2-30CENl1-KCYPtvfEg" + } + } + ], + "fullUrl" : "urn:uuid:1ca3d9ae-1b70-5ad3-9a3f-5057ba8b0c42", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:dD1XvJhxxWW6z_CVc2xeBDPK2-30CENl1-KCYPtvfEg" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:HfAIhmz69hryNiK_A3EFY-8QRZX3jf9kxnAtQYxASlM" + } + } + ], + "fullUrl" : "urn:uuid:8db0d3c9-4daf-5590-9e96-25a7f5543178", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:HfAIhmz69hryNiK_A3EFY-8QRZX3jf9kxnAtQYxASlM" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:1ca3d9ae-1b70-5ad3-9a3f-5057ba8b0c42" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:keMaEFZob7jhYRFUgIy8EsdiYDl5EA4ZbfRx-wTdxcM" + } + } + ], + "fullUrl" : "urn:uuid:a7c06285-24cd-5846-8485-3bf677932e13", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:8db0d3c9-4daf-5590-9e96-25a7f5543178" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:n7olNQTu9n8ejH_8Ri89RIeYCdubpvhza11Dem-Bp1g" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:8a294dd6-c351-54b4-87aa-81ea07206c74" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:108" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-clinical-record-r4.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-clinical-record-r4.json new file mode 100644 index 000000000..ba56e3ea5 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-clinical-record-r4.json @@ -0,0 +1,459 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:9i-0E-cUI0TsDSczTjTYcI9NgI0Sj37B0cjB_iIbHwU" + } + } + ], + "fullUrl" : "urn:uuid:83ea8a42-ca57-5036-9396-5371a81d42f2", + "resource" : { + "author" : [ + { + "reference" : "urn:uuid:6ce02827-8be3-5f4c-ac0b-d593ce6b652e" + }, + { + "reference" : "urn:uuid:5d2abae0-a740-5ed1-a09c-87c5231ff41f" + } + ], + "content" : [ + { + "attachment" : { + "contentType" : "application/fhir+json; fhirVersion=4.0", + "data" : "eyJyZXNvdXJjZVR5cGUiOiJPYnNlcnZhdGlvbiIsImlkIjoiYTFjLXI0Iiwic3RhdHVzIjoiZmluYWwifQ==", + "hash" : "ZmkVpn5jh44tqT+UVA6H4HvLJSM=", + "size" : 61, + "title" : "Lab Result Record" + }, + "format" : { + "code" : "fhir-resource", + "system" : "https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format" + } + } + ], + "date" : "2026-08-17T23:30:00Z", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKClinicalTypeIdentifierLabResultRecord" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:uK449kCRy1LWpHWupLJdSSDRiP43MTQsefAmqUlnm3E" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:9i-0E-cUI0TsDSczTjTYcI9NgI0Sj37B0cjB_iIbHwU" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1", + "type" : { + "coding" : [ + { + "code" : "source-artifact", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Fs_PIKZck9PmqbpCcF-8I9WDRBXXoWGI6FwxRuhGM70" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-clinical-record-document" + ] + }, + "resourceType" : "DocumentReference", + "status" : "current", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "type" : { + "coding" : [ + { + "code" : "lab-result-record", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-clinical-record-type" + } + ] + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:0ZaEu78BGBVrJS72hNRHP9BJYIoyDH4_NE2uMnNat0Y" + } + } + ], + "fullUrl" : "urn:uuid:6ce02827-8be3-5f4c-ac0b-d593ce6b652e", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:0ZaEu78BGBVrJS72hNRHP9BJYIoyDH4_NE2uMnNat0Y" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:ysM31l9j1ZZknb3Zf7D717AwuBtHmZgZSLruLqcbe20" + } + } + ], + "fullUrl" : "urn:uuid:fb6b1511-9d5f-527b-867f-987be2f3be5e", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:ysM31l9j1ZZknb3Zf7D717AwuBtHmZgZSLruLqcbe20" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Pf91x7fs0FQruJ_U1XevBbsGlCUwMfzaL23El8PHGo8" + } + } + ], + "fullUrl" : "urn:uuid:5d2abae0-a740-5ed1-a09c-87c5231ff41f", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Pf91x7fs0FQruJ_U1XevBbsGlCUwMfzaL23El8PHGo8" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:fb6b1511-9d5f-527b-867f-987be2f3be5e" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:nKU9zQR2B1wn8ULfSRkT5LVO1Sjdvv5Pr7syBOjnOaE" + } + } + ], + "fullUrl" : "urn:uuid:002495ff-6eca-5f3c-abb3-53cff983ce75", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:5d2abae0-a740-5ed1-a09c-87c5231ff41f" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:uK449kCRy1LWpHWupLJdSSDRiP43MTQsefAmqUlnm3E" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:83ea8a42-ca57-5036-9396-5371a81d42f2" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:107" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-default-apple-watch-heart-rate.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-default-apple-watch-heart-rate.json new file mode 100644 index 000000000..6746fe2fe --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-default-apple-watch-heart-rate.json @@ -0,0 +1,454 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:zMCh7R3Pw0Ml2WboczVabjSmqd48QAZ9uu3WhUnBUsU" + } + } + ], + "fullUrl" : "urn:uuid:a94bcb1d-a83f-55fe-a9ed-87d2cfa326ab", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "device" : { + "reference" : "urn:uuid:cc6bcd8d-332a-5bbf-9e77-b5491c6e67cd" + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:F43TlTUfeT7bxQ7yRmOOwfI5H8SUIi2i3t9y9W6PYK0" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:zMCh7R3Pw0Ml2WboczVabjSmqd48QAZ9uu3WhUnBUsU" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:dnvu1PDipskgR3C5r_9Ja6R0uD2nDvfTeZSXzaRfvAg" + } + } + ], + "fullUrl" : "urn:uuid:cc6bcd8d-332a-5bbf-9e77-b5491c6e67cd", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:dnvu1PDipskgR3C5r_9Ja6R0uD2nDvfTeZSXzaRfvAg" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:iKyQ-44j1Vk4Qw-sRsHIKikPloSo7C1KOOpKawUWLvo" + } + } + ], + "fullUrl" : "urn:uuid:b096bf0e-0d9e-567c-ba4e-6e67735a8a3c", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:iKyQ-44j1Vk4Qw-sRsHIKikPloSo7C1KOOpKawUWLvo" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:v4H8OI1UD1SI_4yJhVDHYfppz0jBykv2OSpF8S3WIU0" + } + } + ], + "fullUrl" : "urn:uuid:7833501c-dd4a-551c-9137-936726134eb9", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:v4H8OI1UD1SI_4yJhVDHYfppz0jBykv2OSpF8S3WIU0" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:b096bf0e-0d9e-567c-ba4e-6e67735a8a3c" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:LisjRqU2uOBCowdo0gKxH2TYkhgULO8od-ja4-tTX34" + } + } + ], + "fullUrl" : "urn:uuid:4483cc28-5d8e-57ce-9731-f1997b8d6348", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:7833501c-dd4a-551c-9137-936726134eb9" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:F43TlTUfeT7bxQ7yRmOOwfI5H8SUIi2i3t9y9W6PYK0" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:a94bcb1d-a83f-55fe-a9ed-87d2cfa326ab" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:100" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-blood-pressure.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-blood-pressure.json new file mode 100644 index 000000000..738e399bd --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-blood-pressure.json @@ -0,0 +1,607 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:8vqPK5IkIrDkwsqF0FS9IOi0M56-nZgPITlFTuY1UzI" + } + } + ], + "fullUrl" : "urn:uuid:0f6b0b2d-2a49-5ca0-9093-4cfff2bda9fe", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "85354-9", + "display" : "Blood pressure panel with all children optional", + "system" : "http://loinc.org" + } + ] + }, + "component" : [ + { + "code" : { + "coding" : [ + { + "code" : "8480-6", + "system" : "http://loinc.org" + } + ] + }, + "valueQuantity" : { + "code" : "mm[Hg]", + "system" : "http://unitsofmeasure.org", + "unit" : "mmHg", + "value" : 120 + } + }, + { + "code" : { + "coding" : [ + { + "code" : "8462-4", + "system" : "http://loinc.org" + } + ] + }, + "valueQuantity" : { + "code" : "mm[Hg]", + "system" : "http://unitsofmeasure.org", + "unit" : "mmHg", + "value" : 80 + } + } + ], + "device" : { + "reference" : "urn:uuid:628543f0-1b0c-5553-8365-3e150abe4fab" + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKCorrelationTypeIdentifierBloodPressure" + }, + { + "url" : "http://hl7.org/fhir/StructureDefinition/workflow-researchStudy", + "valueReference" : { + "reference" : "urn:uuid:32c07520-83c2-5f7c-b5a2-d8613ea53073", + "type" : "ResearchStudy" + } + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:DtsjmvTnOYCFDrfMTg47m8F_RadoyVJ4I_PXX9u2Wlc" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:8vqPK5IkIrDkwsqF0FS9IOi0M56-nZgPITlFTuY1UzI" + }, + { + "system" : "https://study.example.org/fhir/NamingSystem/healthkit-store", + "value" : "3a7e5c10-0000-4000-8000-0000000000b4" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-pressure", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:research-study:0:be08jqpNMLbTOKb-1vZbH2qcxPGYR1kuCKL8KH-14Ew" + } + } + ], + "fullUrl" : "urn:uuid:32c07520-83c2-5f7c-b5a2-d8613ea53073", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/researchstudy", + "value" : "study-a" + } + ], + "protocol" : [ + { + "reference" : "urn:uuid:3035f5fc-eca9-52dc-83c7-15de76a3a4d2" + } + ], + "resourceType" : "ResearchStudy", + "status" : "active" + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:plan-definition:0:BZ14xVAfCtSsDAmVzAdYBbFTXzTyrzGWXPu-ll-k8hY" + } + } + ], + "fullUrl" : "urn:uuid:3035f5fc-eca9-52dc-83c7-15de76a3a4d2", + "resource" : { + "resourceType" : "PlanDefinition", + "status" : "active", + "url" : "https://study.example.org/PlanDefinition/study-a", + "version" : "1" + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:research-subject:0:EVZ5feUeVj9WLQDw-xeih3FVZQcafQk2c6HJ10SQa9c" + } + } + ], + "fullUrl" : "urn:uuid:94f20352-f9c1-51f6-bbc3-f69ebc887e38", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/researchsubject", + "value" : "enrollment-study-a" + } + ], + "individual" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "resourceType" : "ResearchSubject", + "status" : "on-study", + "study" : { + "reference" : "urn:uuid:32c07520-83c2-5f7c-b5a2-d8613ea53073" + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Jk3QVTEI7BNO5GgYWeHEvFQKdEz0DZEl0_5kiGb2zpQ" + } + } + ], + "fullUrl" : "urn:uuid:628543f0-1b0c-5553-8365-3e150abe4fab", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Jk3QVTEI7BNO5GgYWeHEvFQKdEz0DZEl0_5kiGb2zpQ" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:2XhklGnhjCvKhKDLikIm5BOCudxE6r6oPFErzxYxI2w" + } + } + ], + "fullUrl" : "urn:uuid:4dd018ca-72eb-5a85-a40c-a10566d1e431", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:2XhklGnhjCvKhKDLikIm5BOCudxE6r6oPFErzxYxI2w" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:I83g8Ji521GuMfkwA4N6FF-B4Js7Jetts-DhCDE5txo" + } + } + ], + "fullUrl" : "urn:uuid:e655b5b2-eec0-5e96-9969-fd9fa6bf6436", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Study", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:I83g8Ji521GuMfkwA4N6FF-B4Js7Jetts-DhCDE5txo" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.example.study" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:4dd018ca-72eb-5a85-a40c-a10566d1e431" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "4.1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "build", + "display" : "Build", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "412" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:bavp-4lXBOJcRujUM5vGGBCnci_OUcxtJe7WxSxrzEM" + } + } + ], + "fullUrl" : "urn:uuid:d2d0d7fd-9942-5ddd-b017-d9862e62c890", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:e655b5b2-eec0-5e96-9969-fd9fa6bf6436" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:DtsjmvTnOYCFDrfMTg47m8F_RadoyVJ4I_PXX9u2Wlc" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:0f6b0b2d-2a49-5ca0-9093-4cfff2bda9fe" + } + ] + } + } + ], + "id" : "3A7E5C10-0000-4000-8000-0000000000B4", + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:104" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-electrocardiogram-symptom.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-electrocardiogram-symptom.json new file mode 100644 index 000000000..13ec56278 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-electrocardiogram-symptom.json @@ -0,0 +1,586 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:K9V2p1LjBGEt7K_4B1pyE8qAjp8evO1PfZO0xd60Jvo" + } + } + ], + "fullUrl" : "urn:uuid:788e79d4-c8cf-513b-a47a-b20aa0a24903", + "resource" : { + "code" : { + "coding" : [ + { + "code" : "symptom-chest-tightness-or-pain", + "display" : "Chest tightness or pain", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement" + } + ] + }, + "device" : { + "reference" : "urn:uuid:6f138ea5-3175-5ca2-b29b-766511afdf45" + }, + "effectivePeriod" : { + "_end" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "_start" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "end" : "2026-08-17T15:30:30-07:00", + "start" : "2026-08-17T15:30:00-07:00" + }, + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKCategoryTypeIdentifierChestTightnessOrPain" + }, + { + "url" : "http://hl7.org/fhir/StructureDefinition/workflow-researchStudy", + "valueReference" : { + "reference" : "urn:uuid:0ef6f7b3-92fc-540e-b3fd-aed81fb4d2d2", + "type" : "ResearchStudy" + } + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:fpa5kNlnUtj_xme3hPVThHDLGtoIHU5ngdpFiPze2lw" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:K9V2p1LjBGEt7K_4B1pyE8qAjp8evO1PfZO0xd60Jvo" + }, + { + "system" : "https://study.example.org/fhir/NamingSystem/healthkit-store", + "value" : "3a7e5c10-0000-4000-8000-0000000000b3" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-chest-tightness-or-pain" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueCodeableConcept" : { + "coding" : [ + { + "code" : "mild", + "display" : "Mild", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity" + }, + { + "code" : "mild", + "display" : "Mild", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity" + } + ] + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:research-study:0:Aod_KxRMVv_yCLw87QqkdtQZOh5XpK6O5jD4g9PAIAo" + } + } + ], + "fullUrl" : "urn:uuid:0ef6f7b3-92fc-540e-b3fd-aed81fb4d2d2", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/researchstudy", + "value" : "study-a" + } + ], + "protocol" : [ + { + "reference" : "urn:uuid:d509e54a-5fa7-595c-b03a-2972f47be4a5" + } + ], + "resourceType" : "ResearchStudy", + "status" : "active" + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:plan-definition:0:5ZQCc9PyepE5lStLVX1HcJkVeWaZ1fFPDZuD6TVpjo0" + } + } + ], + "fullUrl" : "urn:uuid:d509e54a-5fa7-595c-b03a-2972f47be4a5", + "resource" : { + "resourceType" : "PlanDefinition", + "status" : "active", + "url" : "https://study.example.org/PlanDefinition/study-a", + "version" : "1" + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:research-subject:0:bzd-eaxDHrnrKcDvT7scGwHsWJYCK-p5nQbOMA0-4GE" + } + } + ], + "fullUrl" : "urn:uuid:c1d0e7db-b0b0-5a1b-a5f8-08ff51e2f7c8", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/researchsubject", + "value" : "enrollment-study-a" + } + ], + "individual" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "resourceType" : "ResearchSubject", + "status" : "on-study", + "study" : { + "reference" : "urn:uuid:0ef6f7b3-92fc-540e-b3fd-aed81fb4d2d2" + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:hBVQdWxJu2wziqVi77ZvUr3p5Qig9BMYg3hneMRlY-4" + } + } + ], + "fullUrl" : "urn:uuid:6f138ea5-3175-5ca2-b29b-766511afdf45", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:hBVQdWxJu2wziqVi77ZvUr3p5Qig9BMYg3hneMRlY-4" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:QaqBwsLByWFpDwmareD3TBysiNXs94H88v-pbTIvSYM" + } + } + ], + "fullUrl" : "urn:uuid:ec6f8558-0b5a-5df1-8513-b0aafae836d8", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:QaqBwsLByWFpDwmareD3TBysiNXs94H88v-pbTIvSYM" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:ZLmmGKOulCG8sSiD2VFjIQF7ak7mYbapy-nNuHzE8sk" + } + } + ], + "fullUrl" : "urn:uuid:66386093-a42c-500d-9a75-8ee7fa233523", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Study", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:ZLmmGKOulCG8sSiD2VFjIQF7ak7mYbapy-nNuHzE8sk" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.example.study" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:ec6f8558-0b5a-5df1-8513-b0aafae836d8" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "4.1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "build", + "display" : "Build", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "412" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:k2kdDju8TTlCq6pmX3lHMAalluOEIu9BAtVqvakWoDw" + } + } + ], + "fullUrl" : "urn:uuid:97f0632f-95f7-5c3a-b4b9-a007ed1aa67b", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:66386093-a42c-500d-9a75-8ee7fa233523" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:fpa5kNlnUtj_xme3hPVThHDLGtoIHU5ngdpFiPze2lw" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:788e79d4-c8cf-513b-a47a-b20aa0a24903" + } + ] + } + } + ], + "id" : "3A7E5C10-0000-4000-8000-0000000000B3", + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:102" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-electrocardiogram.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-electrocardiogram.json new file mode 100644 index 000000000..df0c5d7f5 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-electrocardiogram.json @@ -0,0 +1,744 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:OFv8xcXen2S9ewx-C_x6Kf_LK21ZvQR443wn4GQknhw" + } + } + ], + "fullUrl" : "urn:uuid:574888fe-6207-503b-bda8-4248d5e9069b", + "resource" : { + "code" : { + "coding" : [ + { + "code" : "11524-6", + "display" : "EKG study", + "system" : "http://loinc.org" + } + ] + }, + "component" : [ + { + "code" : { + "coding" : [ + { + "code" : "131329", + "display" : "MDC_ECG_ELEC_POTL_I", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "valueSampledData" : { + "data" : "0.125 0.25 -0.125 0", + "dimensions" : 1, + "origin" : { + "code" : "mV", + "system" : "http://unitsofmeasure.org", + "unit" : "mV", + "value" : 0 + }, + "period" : 2 + } + } + ], + "device" : { + "reference" : "urn:uuid:b122b8dd-5e58-5c54-a555-ece41c312432" + }, + "effectivePeriod" : { + "end" : "2026-08-17T15:30:00.256-07:00", + "start" : "2026-08-17T15:30:00.25-07:00" + }, + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKDataTypeIdentifierElectrocardiogram" + }, + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status", + "valueCode" : "present" + }, + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period", + "valuePeriod" : { + "end" : "2026-08-17T15:30:30-07:00", + "start" : "2026-08-17T15:30:00-07:00" + } + }, + { + "url" : "http://hl7.org/fhir/StructureDefinition/workflow-researchStudy", + "valueReference" : { + "reference" : "urn:uuid:2c421d60-c381-561b-ac4d-d0693b151273", + "type" : "ResearchStudy" + } + } + ], + "hasMember" : [ + { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:K9V2p1LjBGEt7K_4B1pyE8qAjp8evO1PfZO0xd60Jvo" + }, + "type" : "Observation" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Z0jDsNvEd05V7-ne3fOCDWvISewHM5tY7RU4djTJ6Sg" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:OFv8xcXen2S9ewx-C_x6Kf_LK21ZvQR443wn4GQknhw" + }, + { + "system" : "https://study.example.org/fhir/NamingSystem/healthkit-store", + "value" : "3a7e5c10-0000-4000-8000-0000000000b2" + } + ], + "interpretation" : [ + { + "coding" : [ + { + "code" : "sinusRhythm", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification" + } + ] + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation" + ] + }, + "method" : { + "coding" : [ + { + "code" : "version2", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version" + } + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Qyf9Ap8mTGvVWuzwOGkQykvoKnE9XhZNfvoHcjXJi-M" + } + } + ], + "fullUrl" : "urn:uuid:f9ad7f61-d875-5baa-81ea-7ec7b93f18d4", + "resource" : { + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "derivedFrom" : [ + { + "reference" : "urn:uuid:574888fe-6207-503b-bda8-4248d5e9069b" + } + ], + "device" : { + "reference" : "urn:uuid:b122b8dd-5e58-5c54-a555-ece41c312432" + }, + "effectivePeriod" : { + "end" : "2026-08-17T15:30:00.256-07:00", + "start" : "2026-08-17T15:30:00.25-07:00" + }, + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKDataTypeIdentifierElectrocardiogram" + }, + { + "url" : "http://hl7.org/fhir/StructureDefinition/workflow-researchStudy", + "valueReference" : { + "reference" : "urn:uuid:2c421d60-c381-561b-ac4d-d0693b151273", + "type" : "ResearchStudy" + } + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Z0jDsNvEd05V7-ne3fOCDWvISewHM5tY7RU4djTJ6Sg" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Qyf9Ap8mTGvVWuzwOGkQykvoKnE9XhZNfvoHcjXJi-M" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:research-study:0:8sqRlinUPMk--cgt2v137ew5NmG2RH4EW_5kClc-HNE" + } + } + ], + "fullUrl" : "urn:uuid:2c421d60-c381-561b-ac4d-d0693b151273", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/researchstudy", + "value" : "study-a" + } + ], + "protocol" : [ + { + "reference" : "urn:uuid:10d7a091-c59c-5645-a946-1f5945a7c03f" + } + ], + "resourceType" : "ResearchStudy", + "status" : "active" + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:plan-definition:0:YpGvgqVshX7KTF-Te07Ky6jQByKPOdvQFMjfXx8TMlw" + } + } + ], + "fullUrl" : "urn:uuid:10d7a091-c59c-5645-a946-1f5945a7c03f", + "resource" : { + "resourceType" : "PlanDefinition", + "status" : "active", + "url" : "https://study.example.org/PlanDefinition/study-a", + "version" : "1" + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:research-subject:0:69m7dEAvDXCRjHj8SMH135uW9ku4D7HlrPuNoISl0rU" + } + } + ], + "fullUrl" : "urn:uuid:6c9cc6d4-2d8c-53b7-8d50-522a6b694fca", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/researchsubject", + "value" : "enrollment-study-a" + } + ], + "individual" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "resourceType" : "ResearchSubject", + "status" : "on-study", + "study" : { + "reference" : "urn:uuid:2c421d60-c381-561b-ac4d-d0693b151273" + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:XrEDL-WsGTY9jGMHasq3Rt_USbZtgnIAlBM99sBAAuo" + } + } + ], + "fullUrl" : "urn:uuid:b122b8dd-5e58-5c54-a555-ece41c312432", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:XrEDL-WsGTY9jGMHasq3Rt_USbZtgnIAlBM99sBAAuo" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:N9r1fzR6yTA-Yx6p2DmPwqvmjoNjeE3Fn_OXZXDtJhM" + } + } + ], + "fullUrl" : "urn:uuid:f89fda49-7713-5c37-9d27-98cfade99f6e", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:N9r1fzR6yTA-Yx6p2DmPwqvmjoNjeE3Fn_OXZXDtJhM" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:UPcito-tvEnghPpD39N6ddChtuDWevTdwr9X8fcYX6k" + } + } + ], + "fullUrl" : "urn:uuid:c4fd062f-9381-5aa0-9395-18b003676561", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Study", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:UPcito-tvEnghPpD39N6ddChtuDWevTdwr9X8fcYX6k" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.example.study" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:f89fda49-7713-5c37-9d27-98cfade99f6e" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "4.1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "build", + "display" : "Build", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "412" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:9ySYjUs180Ye7JQvXjMFgGIdVkn9ugVhXkHDPdyHWn4" + } + } + ], + "fullUrl" : "urn:uuid:cfdd6398-52de-5095-ac9a-54549341ac17", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:c4fd062f-9381-5aa0-9395-18b003676561" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Z0jDsNvEd05V7-ne3fOCDWvISewHM5tY7RU4djTJ6Sg" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:574888fe-6207-503b-bda8-4248d5e9069b" + }, + { + "reference" : "urn:uuid:f9ad7f61-d875-5baa-81ea-7ec7b93f18d4" + } + ] + } + } + ], + "id" : "3A7E5C10-0000-4000-8000-0000000000B2", + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:103" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-own-heart-rate.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-own-heart-rate.json new file mode 100644 index 000000000..2a44ae9ad --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-own-heart-rate.json @@ -0,0 +1,737 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:CR04mZJUxRK7xXGAagUV0xEWWmHxRoClZ6yg1Bw1i20" + } + } + ], + "fullUrl" : "urn:uuid:1e0560b2-13f2-52c3-bc67-ee22ee6b0491", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "device" : { + "reference" : "urn:uuid:07ec9f61-83e3-55cb-a992-66dcbec88596" + }, + "effectiveDateTime" : "2026-08-17T15:30:00.512-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + }, + { + "url" : "http://hl7.org/fhir/StructureDefinition/observation-gatewayDevice", + "valueReference" : { + "reference" : "urn:uuid:3fd668e6-391c-52d9-a75c-e7457ef7f612" + } + }, + { + "url" : "http://hl7.org/fhir/StructureDefinition/workflow-researchStudy", + "valueReference" : { + "reference" : "urn:uuid:0f6012d0-4383-5a65-be41-61d1e94a120c", + "type" : "ResearchStudy" + } + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:KZGJ-PcDN04ZoVNJYRArjDpRHlUpuRqUxgeiOXceUKs" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:CR04mZJUxRK7xXGAagUV0xEWWmHxRoClZ6yg1Bw1i20" + }, + { + "system" : "https://study.example.org/fhir/NamingSystem/healthkit-store", + "value" : "3a7e5c10-0000-4000-8000-0000000000b1" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 64 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:research-study:0:64kOCN9XVt_LBm7pH5Q-U-nPWQgnkZF-xZZrs2kn8eM" + } + } + ], + "fullUrl" : "urn:uuid:0f6012d0-4383-5a65-be41-61d1e94a120c", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/researchstudy", + "value" : "study-a" + } + ], + "protocol" : [ + { + "reference" : "urn:uuid:88f001f7-ffdb-5419-94ab-44bb427a36a9" + } + ], + "resourceType" : "ResearchStudy", + "status" : "active" + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:plan-definition:0:K6Skrb4jB2KrWEx-lbUWJkhk5Ebd5MB1pFDHbhbJr1o" + } + } + ], + "fullUrl" : "urn:uuid:88f001f7-ffdb-5419-94ab-44bb427a36a9", + "resource" : { + "resourceType" : "PlanDefinition", + "status" : "active", + "url" : "https://study.example.org/PlanDefinition/study-a", + "version" : "1" + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:research-subject:0:LFF6sj-nCl27eYeRqpPD5cExKRn76lZGzDfJY3RPMD4" + } + } + ], + "fullUrl" : "urn:uuid:cf154062-6840-5e44-9816-2848563d49aa", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/researchsubject", + "value" : "enrollment-study-a" + } + ], + "individual" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "resourceType" : "ResearchSubject", + "status" : "on-study", + "study" : { + "reference" : "urn:uuid:0f6012d0-4383-5a65-be41-61d1e94a120c" + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:tbLME749h7SrST8Z96kIH9-OEbSHoRxVa_76OuIRGw8" + } + } + ], + "fullUrl" : "urn:uuid:07ec9f61-83e3-55cb-a992-66dcbec88596", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:tbLME749h7SrST8Z96kIH9-OEbSHoRxVa_76OuIRGw8" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:VX9nEV6R_NnDJQfjSaV3RFLem5GGkpQcuOS_pgnvzRA" + } + } + ], + "fullUrl" : "urn:uuid:1eccfcb0-e765-5202-bf41-5cc113f7b912", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:VX9nEV6R_NnDJQfjSaV3RFLem5GGkpQcuOS_pgnvzRA" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:g-oQPZ1Qw_M7v2NRKGr8NsuxMD5qi_RPCOV3r5XhAC8" + } + } + ], + "fullUrl" : "urn:uuid:3fd668e6-391c-52d9-a75c-e7457ef7f612", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Study", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:g-oQPZ1Qw_M7v2NRKGr8NsuxMD5qi_RPCOV3r5XhAC8" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.example.study" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:1eccfcb0-e765-5202-bf41-5cc113f7b912" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "4.1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "build", + "display" : "Build", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "412" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:LbK09_orUogXd2GgFuk5Cy4QwuagA9EUijOa6XuhSfs" + } + } + ], + "fullUrl" : "urn:uuid:daa483bd-5fb6-5585-b76a-7e9ae913d3f0", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:LbK09_orUogXd2GgFuk5Cy4QwuagA9EUijOa6XuhSfs" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "iPhone17,1", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "26.1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:nKyJ16XGdLTGWDUFV8HHRw4Ftjw-exSwrgKRcR2b0y8" + } + } + ], + "fullUrl" : "urn:uuid:139b1dbc-ffe8-5021-818a-de33c0b27e14", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Study", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:nKyJ16XGdLTGWDUFV8HHRw4Ftjw-exSwrgKRcR2b0y8" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.example.study" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:daa483bd-5fb6-5585-b76a-7e9ae913d3f0" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "412" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:1D2GNiybkAh2eCrrgLpL56GAi2QCClnCJg3yvYZECxI" + } + } + ], + "fullUrl" : "urn:uuid:3e96386d-7b5f-5a56-a0ad-3305ee42e2b9", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:3fd668e6-391c-52d9-a75c-e7457ef7f612" + } + } + ], + "entity" : [ + { + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "author", + "display" : "Author", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:139b1dbc-ffe8-5021-818a-de33c0b27e14" + } + } + ], + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:KZGJ-PcDN04ZoVNJYRArjDpRHlUpuRqUxgeiOXceUKs" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:1e0560b2-13f2-52c3-bc67-ee22ee6b0491" + } + ] + } + } + ], + "id" : "3A7E5C10-0000-4000-8000-0000000000B1", + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:101" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-retraction.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-retraction.json new file mode 100644 index 000000000..995bd7354 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-retraction.json @@ -0,0 +1,144 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:retraction-provenance:0:ms0rpnt6afHbyHhp9hkSASzqJKh2q_4XHREv3TUb0MA" + } + } + ], + "fullUrl" : "urn:uuid:6d9fa291-efa7-5bb5-a49d-48bad1caf041", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "source-record-retracted", + "display" : "Source record retracted", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-lifecycle-event" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:LsCZJAYOc6vExry-78Wa2zbtxObjNLQb0cdjQivtwlM" + }, + "type" : "Device" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:ZpRQSARlg2qkQHwRcBVu8-oUdWZhbP4dYnyLqjWHMe4" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-retraction-provenance" + ] + }, + "occurredPeriod" : { + "end" : "2026-08-17T23:29:59.75Z", + "start" : "2026-08-17T22:30:00.125Z" + }, + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-retraction-target-role", + "valueCode" : "primary-output" + }, + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-retraction-target-native-identifier", + "valueIdentifier" : { + "system" : "https://study.example.org/fhir/NamingSystem/healthkit-store", + "value" : "3a7e5c10-0000-4000-8000-0000000000b8" + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:pjjXIFyf2SMsPd0ngaDGLMwiEu4wTwcEjvIB_J4WlLI" + }, + "type" : "Observation" + } + ] + } + } + ], + "id" : "3A7E5C10-0000-4000-8000-0000000000B8", + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:106" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-retraction-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-state-of-mind.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-state-of-mind.json new file mode 100644 index 000000000..8e6db7412 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-state-of-mind.json @@ -0,0 +1,548 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Kb32ohff3sFflnWGrREZSf1_z1RqyVDuTrYNztttbhU" + } + } + ], + "fullUrl" : "urn:uuid:a1947f94-e15e-538c-87fb-a5ca488d0d74", + "resource" : { + "code" : { + "coding" : [ + { + "code" : "state-of-mind", + "display" : "State of mind", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement" + } + ] + }, + "component" : [ + { + "code" : { + "coding" : [ + { + "code" : "kind", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement" + } + ] + }, + "valueCodeableConcept" : { + "coding" : [ + { + "code" : "daily-mood", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind" + } + ] + } + }, + { + "code" : { + "coding" : [ + { + "code" : "valence-classification", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement" + } + ] + }, + "valueCodeableConcept" : { + "coding" : [ + { + "code" : "slightly-unpleasant", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification" + } + ] + } + }, + { + "code" : { + "coding" : [ + { + "code" : "state-of-mind-label", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement" + } + ] + }, + "valueCodeableConcept" : { + "coding" : [ + { + "code" : "stressed", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label" + } + ] + } + }, + { + "code" : { + "coding" : [ + { + "code" : "state-of-mind-association", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement" + } + ] + }, + "valueCodeableConcept" : { + "coding" : [ + { + "code" : "health", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association" + } + ] + } + } + ], + "effectivePeriod" : { + "_end" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "_start" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "end" : "2026-08-17T15:30:00-07:00", + "start" : "2026-08-17T15:30:00-07:00" + }, + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKDataTypeStateOfMind" + }, + { + "url" : "http://hl7.org/fhir/StructureDefinition/workflow-researchStudy", + "valueReference" : { + "reference" : "urn:uuid:a462d7a0-3a74-5ce8-bc0d-d39de55cfd79", + "type" : "ResearchStudy" + } + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:b_LSS9ukw4_W6ZJju_Zqey0ojqEWqiV75AuWYp1Swig" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Kb32ohff3sFflnWGrREZSf1_z1RqyVDuTrYNztttbhU" + }, + { + "system" : "https://study.example.org/fhir/NamingSystem/healthkit-store", + "value" : "3a7e5c10-0000-4000-8000-0000000000b7" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "1", + "system" : "http://unitsofmeasure.org", + "unit" : "valence", + "value" : -0.25 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:research-study:0:OOo3y8H257L5YYcL2UghsQY5WzBRNydt65F0x23hkmY" + } + } + ], + "fullUrl" : "urn:uuid:a462d7a0-3a74-5ce8-bc0d-d39de55cfd79", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/researchstudy", + "value" : "study-a" + } + ], + "protocol" : [ + { + "reference" : "urn:uuid:5cf9e99d-5e05-5dcb-9087-d58889470973" + } + ], + "resourceType" : "ResearchStudy", + "status" : "active" + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:plan-definition:0:BlM0ojbFx-MONJNhLEe-J6Wk3z-zC4vWKvJr6dyNLqg" + } + } + ], + "fullUrl" : "urn:uuid:5cf9e99d-5e05-5dcb-9087-d58889470973", + "resource" : { + "resourceType" : "PlanDefinition", + "status" : "active", + "url" : "https://study.example.org/PlanDefinition/study-a", + "version" : "1" + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:research-subject:0:MS_cgxLm7OUXJYcdZiD2sZvl_PrXLaPMXxyIZ2MuJfc" + } + } + ], + "fullUrl" : "urn:uuid:cd550c5b-8f9b-5ec8-86b7-d7f98f5084ff", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/researchsubject", + "value" : "enrollment-study-a" + } + ], + "individual" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "resourceType" : "ResearchSubject", + "status" : "on-study", + "study" : { + "reference" : "urn:uuid:a462d7a0-3a74-5ce8-bc0d-d39de55cfd79" + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:I1anqEt-rBlhVEBQjldnmNn1NdwltkdXnR8BEZNOhbA" + } + } + ], + "fullUrl" : "urn:uuid:965fd1e4-ea7c-5ccc-bba0-0fc42741b390", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:I1anqEt-rBlhVEBQjldnmNn1NdwltkdXnR8BEZNOhbA" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:sP96FCOlApeZ5B9yq74Vpm08s-yE4NGJg2Glk90AAeU" + } + } + ], + "fullUrl" : "urn:uuid:6fb676b7-6ba3-506e-a862-86b7dc093934", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Study", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:sP96FCOlApeZ5B9yq74Vpm08s-yE4NGJg2Glk90AAeU" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.example.study" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:965fd1e4-ea7c-5ccc-bba0-0fc42741b390" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "4.1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "build", + "display" : "Build", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "412" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:EYJBp1rLxQV_y7RzEoDNQaPIF2b36nluu4OiAbJ7FS8" + } + } + ], + "fullUrl" : "urn:uuid:d8a1461b-abd1-5ca2-bb53-5e1bcea156e1", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:6fb676b7-6ba3-506e-a862-86b7dc093934" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:b_LSS9ukw4_W6ZJju_Zqey0ojqEWqiV75AuWYp1Swig" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:a1947f94-e15e-538c-87fb-a5ca488d0d74" + } + ] + } + } + ], + "id" : "3A7E5C10-0000-4000-8000-0000000000B7", + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:105" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json index d24dd93a8..7ce49e904 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json @@ -435,6 +435,690 @@ ] }, + "exporter-clinical-record-dstu2" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:8a294dd6-c351-54b4-87aa-81ea07206c74", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:n7olNQTu9n8ejH_8Ri89RIeYCdubpvhza11Dem-Bp1g", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:wvo023yNyjR7BIhh_qtuM14UFTeC7ZMjdsu-ibC2fq4", + "source-artifact|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1|v0:test:1:8rDEE7xtphneUrfgNiC_HhpPvozXPYQGtURrEi2Wv6w" + ], + "resourceType" : "DocumentReference" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:d877d103-d777-5daf-b873-772c75e77e36", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:MsCECHvfM6JqFvbWOA4zwLJukhZ-qjAPd-zmwG-86pA", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:1ca3d9ae-1b70-5ad3-9a3f-5057ba8b0c42", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:dD1XvJhxxWW6z_CVc2xeBDPK2-30CENl1-KCYPtvfEg" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:8db0d3c9-4daf-5590-9e96-25a7f5543178", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:HfAIhmz69hryNiK_A3EFY-8QRZX3jf9kxnAtQYxASlM", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:a7c06285-24cd-5846-8485-3bf677932e13", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "exporter-clinical-record-r4" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:83ea8a42-ca57-5036-9396-5371a81d42f2", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:uK449kCRy1LWpHWupLJdSSDRiP43MTQsefAmqUlnm3E", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:9i-0E-cUI0TsDSczTjTYcI9NgI0Sj37B0cjB_iIbHwU", + "source-artifact|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1|v0:test:1:Fs_PIKZck9PmqbpCcF-8I9WDRBXXoWGI6FwxRuhGM70" + ], + "resourceType" : "DocumentReference" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:6ce02827-8be3-5f4c-ac0b-d593ce6b652e", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:0ZaEu78BGBVrJS72hNRHP9BJYIoyDH4_NE2uMnNat0Y", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:fb6b1511-9d5f-527b-867f-987be2f3be5e", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:ysM31l9j1ZZknb3Zf7D717AwuBtHmZgZSLruLqcbe20" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:5d2abae0-a740-5ed1-a09c-87c5231ff41f", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:Pf91x7fs0FQruJ_U1XevBbsGlCUwMfzaL23El8PHGo8", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:002495ff-6eca-5f3c-abb3-53cff983ce75", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "exporter-default-apple-watch-heart-rate" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:a94bcb1d-a83f-55fe-a9ed-87d2cfa326ab", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:F43TlTUfeT7bxQ7yRmOOwfI5H8SUIi2i3t9y9W6PYK0", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:zMCh7R3Pw0Ml2WboczVabjSmqd48QAZ9uu3WhUnBUsU" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:cc6bcd8d-332a-5bbf-9e77-b5491c6e67cd", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:dnvu1PDipskgR3C5r_9Ja6R0uD2nDvfTeZSXzaRfvAg", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:b096bf0e-0d9e-567c-ba4e-6e67735a8a3c", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:iKyQ-44j1Vk4Qw-sRsHIKikPloSo7C1KOOpKawUWLvo" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:7833501c-dd4a-551c-9137-936726134eb9", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:v4H8OI1UD1SI_4yJhVDHYfppz0jBykv2OSpF8S3WIU0", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:4483cc28-5d8e-57ce-9731-f1997b8d6348", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "exporter-deployment-blood-pressure" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "http://hl7.org/fhir/StructureDefinition/workflow-researchStudy" + ], + "fullUrl" : "urn:uuid:0f6b0b2d-2a49-5ca0-9093-4cfff2bda9fe", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:DtsjmvTnOYCFDrfMTg47m8F_RadoyVJ4I_PXX9u2Wlc", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:8vqPK5IkIrDkwsqF0FS9IOi0M56-nZgPITlFTuY1UzI", + "-|https://study.example.org/fhir/NamingSystem/healthkit-store|3a7e5c10-0000-4000-8000-0000000000b4" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:32c07520-83c2-5f7c-b5a2-d8613ea53073", + "identifiers" : [ + "-|https://grovealliance.org/fhir/testing/identifiers/researchstudy|study-a" + ], + "resourceType" : "ResearchStudy" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:3035f5fc-eca9-52dc-83c7-15de76a3a4d2", + "identifiers" : [ + + ], + "resourceType" : "PlanDefinition" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:94f20352-f9c1-51f6-bbc3-f69ebc887e38", + "identifiers" : [ + "-|https://grovealliance.org/fhir/testing/identifiers/researchsubject|enrollment-study-a" + ], + "resourceType" : "ResearchSubject" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:628543f0-1b0c-5553-8365-3e150abe4fab", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:Jk3QVTEI7BNO5GgYWeHEvFQKdEz0DZEl0_5kiGb2zpQ", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:4dd018ca-72eb-5a85-a40c-a10566d1e431", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:2XhklGnhjCvKhKDLikIm5BOCudxE6r6oPFErzxYxI2w" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:e655b5b2-eec0-5e96-9969-fd9fa6bf6436", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:I83g8Ji521GuMfkwA4N6FF-B4Js7Jetts-DhCDE5txo", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.study" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:d2d0d7fd-9942-5ddd-b017-d9862e62c890", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "exporter-deployment-electrocardiogram" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period", + "http://hl7.org/fhir/StructureDefinition/workflow-researchStudy" + ], + "fullUrl" : "urn:uuid:574888fe-6207-503b-bda8-4248d5e9069b", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:Z0jDsNvEd05V7-ne3fOCDWvISewHM5tY7RU4djTJ6Sg", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:OFv8xcXen2S9ewx-C_x6Kf_LK21ZvQR443wn4GQknhw", + "-|https://study.example.org/fhir/NamingSystem/healthkit-store|3a7e5c10-0000-4000-8000-0000000000b2" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "http://hl7.org/fhir/StructureDefinition/workflow-researchStudy" + ], + "fullUrl" : "urn:uuid:f9ad7f61-d875-5baa-81ea-7ec7b93f18d4", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:Z0jDsNvEd05V7-ne3fOCDWvISewHM5tY7RU4djTJ6Sg", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:Qyf9Ap8mTGvVWuzwOGkQykvoKnE9XhZNfvoHcjXJi-M" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:2c421d60-c381-561b-ac4d-d0693b151273", + "identifiers" : [ + "-|https://grovealliance.org/fhir/testing/identifiers/researchstudy|study-a" + ], + "resourceType" : "ResearchStudy" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:10d7a091-c59c-5645-a946-1f5945a7c03f", + "identifiers" : [ + + ], + "resourceType" : "PlanDefinition" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:6c9cc6d4-2d8c-53b7-8d50-522a6b694fca", + "identifiers" : [ + "-|https://grovealliance.org/fhir/testing/identifiers/researchsubject|enrollment-study-a" + ], + "resourceType" : "ResearchSubject" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:b122b8dd-5e58-5c54-a555-ece41c312432", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:XrEDL-WsGTY9jGMHasq3Rt_USbZtgnIAlBM99sBAAuo", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:f89fda49-7713-5c37-9d27-98cfade99f6e", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:N9r1fzR6yTA-Yx6p2DmPwqvmjoNjeE3Fn_OXZXDtJhM" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:c4fd062f-9381-5aa0-9395-18b003676561", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:UPcito-tvEnghPpD39N6ddChtuDWevTdwr9X8fcYX6k", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.study" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:cfdd6398-52de-5095-ac9a-54549341ac17", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "exporter-deployment-electrocardiogram-symptom" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "http://hl7.org/fhir/StructureDefinition/workflow-researchStudy" + ], + "fullUrl" : "urn:uuid:788e79d4-c8cf-513b-a47a-b20aa0a24903", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:fpa5kNlnUtj_xme3hPVThHDLGtoIHU5ngdpFiPze2lw", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:K9V2p1LjBGEt7K_4B1pyE8qAjp8evO1PfZO0xd60Jvo", + "-|https://study.example.org/fhir/NamingSystem/healthkit-store|3a7e5c10-0000-4000-8000-0000000000b3" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:0ef6f7b3-92fc-540e-b3fd-aed81fb4d2d2", + "identifiers" : [ + "-|https://grovealliance.org/fhir/testing/identifiers/researchstudy|study-a" + ], + "resourceType" : "ResearchStudy" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:d509e54a-5fa7-595c-b03a-2972f47be4a5", + "identifiers" : [ + + ], + "resourceType" : "PlanDefinition" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:c1d0e7db-b0b0-5a1b-a5f8-08ff51e2f7c8", + "identifiers" : [ + "-|https://grovealliance.org/fhir/testing/identifiers/researchsubject|enrollment-study-a" + ], + "resourceType" : "ResearchSubject" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:6f138ea5-3175-5ca2-b29b-766511afdf45", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:hBVQdWxJu2wziqVi77ZvUr3p5Qig9BMYg3hneMRlY-4", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:ec6f8558-0b5a-5df1-8513-b0aafae836d8", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:QaqBwsLByWFpDwmareD3TBysiNXs94H88v-pbTIvSYM" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:66386093-a42c-500d-9a75-8ee7fa233523", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:ZLmmGKOulCG8sSiD2VFjIQF7ak7mYbapy-nNuHzE8sk", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.study" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:97f0632f-95f7-5c3a-b4b9-a007ed1aa67b", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "exporter-deployment-own-heart-rate" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "http://hl7.org/fhir/StructureDefinition/observation-gatewayDevice", + "http://hl7.org/fhir/StructureDefinition/workflow-researchStudy" + ], + "fullUrl" : "urn:uuid:1e0560b2-13f2-52c3-bc67-ee22ee6b0491", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:KZGJ-PcDN04ZoVNJYRArjDpRHlUpuRqUxgeiOXceUKs", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:CR04mZJUxRK7xXGAagUV0xEWWmHxRoClZ6yg1Bw1i20", + "-|https://study.example.org/fhir/NamingSystem/healthkit-store|3a7e5c10-0000-4000-8000-0000000000b1" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:0f6012d0-4383-5a65-be41-61d1e94a120c", + "identifiers" : [ + "-|https://grovealliance.org/fhir/testing/identifiers/researchstudy|study-a" + ], + "resourceType" : "ResearchStudy" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:88f001f7-ffdb-5419-94ab-44bb427a36a9", + "identifiers" : [ + + ], + "resourceType" : "PlanDefinition" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:cf154062-6840-5e44-9816-2848563d49aa", + "identifiers" : [ + "-|https://grovealliance.org/fhir/testing/identifiers/researchsubject|enrollment-study-a" + ], + "resourceType" : "ResearchSubject" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:07ec9f61-83e3-55cb-a992-66dcbec88596", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:tbLME749h7SrST8Z96kIH9-OEbSHoRxVa_76OuIRGw8", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:1eccfcb0-e765-5202-bf41-5cc113f7b912", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:VX9nEV6R_NnDJQfjSaV3RFLem5GGkpQcuOS_pgnvzRA" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:3fd668e6-391c-52d9-a75c-e7457ef7f612", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:g-oQPZ1Qw_M7v2NRKGr8NsuxMD5qi_RPCOV3r5XhAC8", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.study" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:daa483bd-5fb6-5585-b76a-7e9ae913d3f0", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:LbK09_orUogXd2GgFuk5Cy4QwuagA9EUijOa6XuhSfs" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:139b1dbc-ffe8-5021-818a-de33c0b27e14", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:nKyJ16XGdLTGWDUFV8HHRw4Ftjw-exSwrgKRcR2b0y8", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.study" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:3e96386d-7b5f-5a56-a0ad-3305ee42e2b9", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "exporter-deployment-retraction" : { + "entries" : [ + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:6d9fa291-efa7-5bb5-a49d-48bad1caf041", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, + "exporter-deployment-state-of-mind" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "http://hl7.org/fhir/StructureDefinition/workflow-researchStudy" + ], + "fullUrl" : "urn:uuid:a1947f94-e15e-538c-87fb-a5ca488d0d74", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:b_LSS9ukw4_W6ZJju_Zqey0ojqEWqiV75AuWYp1Swig", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:Kb32ohff3sFflnWGrREZSf1_z1RqyVDuTrYNztttbhU", + "-|https://study.example.org/fhir/NamingSystem/healthkit-store|3a7e5c10-0000-4000-8000-0000000000b7" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:a462d7a0-3a74-5ce8-bc0d-d39de55cfd79", + "identifiers" : [ + "-|https://grovealliance.org/fhir/testing/identifiers/researchstudy|study-a" + ], + "resourceType" : "ResearchStudy" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:5cf9e99d-5e05-5dcb-9087-d58889470973", + "identifiers" : [ + + ], + "resourceType" : "PlanDefinition" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:cd550c5b-8f9b-5ec8-86b7-d7f98f5084ff", + "identifiers" : [ + "-|https://grovealliance.org/fhir/testing/identifiers/researchsubject|enrollment-study-a" + ], + "resourceType" : "ResearchSubject" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:965fd1e4-ea7c-5ccc-bba0-0fc42741b390", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:I1anqEt-rBlhVEBQjldnmNn1NdwltkdXnR8BEZNOhbA" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:6fb676b7-6ba3-506e-a862-86b7dc093934", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:sP96FCOlApeZ5B9yq74Vpm08s-yE4NGJg2Glk90AAeU", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.example.study" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:d8a1461b-abd1-5ca2-bb53-5e1bcea156e1", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, "gateway-application-role" : { "entries" : [ { diff --git a/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift b/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift index 310887544..9b717abd7 100644 --- a/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift +++ b/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift @@ -51,6 +51,16 @@ enum StoredSampleFixtures { var writer: Writer } + #if !os(watchOS) + /// The FHIR resource a provider issued, as an `HKClinicalRecord` carries it. + struct ClinicalResource { + var version: HKFHIRVersion + var type: HKFHIRResourceType + var identifier: String + var data: Data + } + #endif + enum FixtureError: Error, CustomStringConvertible { case classNotConstructible(String) case keyNotHonored(key: String, class: String) @@ -118,6 +128,33 @@ enum StoredSampleFixtures { return sample } + #if !os(watchOS) + /// An `HKClinicalRecord` carrying `resource` as the provider's FHIR resource, the way a fetched record carries it; + /// HealthKit offers no initializer for either class. Fails unless the record reads every value back. + static func clinicalRecord( + _ type: HKClinicalTypeIdentifier, + shape: SeriesShape, + displayName: String, + resource: ClinicalResource + ) throws -> HKClinicalRecord { + let fhirResource = try allocate(HKFHIRResource.self) + try write(resource.version, to: "FHIRVersion", of: fhirResource) + try write(resource.type.rawValue, to: "resourceType", of: fhirResource) + try write(resource.identifier, to: "identifier", of: fhirResource) + try write(resource.data, to: "data", of: fhirResource) + let record = try seriesSample(HKClinicalRecord.self, sampleType: HKClinicalType(type), shape: shape) + try write(displayName, to: "displayName", of: record) + try write(fhirResource, to: "FHIRResource", of: record) + guard record.displayName == displayName, + record.fhirResource?.data == resource.data, + record.fhirResource?.resourceType == resource.type, + record.fhirResource?.fhirVersion.fhirRelease == resource.version.fhirRelease else { + throw FixtureError.keyNotHonored(key: "displayName/FHIRResource", class: String(describing: HKClinicalRecord.self)) + } + return record + } + #endif + /// Whether every private ivar the fixtures write still exists, checked before a single value is written. static func privateStorageIsPresent() -> Bool { (objectKeys.allSatisfy { class_getInstanceVariable(HKObject.self, "_\($0)") != nil }) From 1c2f2a7c6ba1c1d4163d989512939912b1db0285 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 14:24:11 +0200 Subject: [PATCH 027/220] Close the Audit's Surviving Content Mutations and Read Entry Method Once Fix-round step G3, audit ledger section 1 confirmed findings 1 (six realistic regressions passed the suite), 3 (the public ECG evidence path has no test), 6 (unit-converted values are untested anywhere) and 9 (the ECG test seam lets the evidence and the sample metadata disagree on the entry method). The audit's six mutations (SP/audit-vgoldcov-mine, sites relocated at 28f93119) all still passed the whole suite at 28f93119 (274 total, 272 passed, 2 skipped each). After this commit and the exporter goldens of the previous one, five fail; the sixth is equivalent on the wire: - M1 notification category mapping (values[value] -> the largest key's code): equivalent. The only notification table with more than one value is walking steadiness, which every code it can pick leaves refused (contract admits only low/very-low; bug present in both trees, audit differential). Track 3's FX-walking-steadiness makes it observable and re-runs it. - M2 atrial fibrillation coded inconclusiveOther: fails the new classificationsStateTheGuideCodes. - M3 assessment score + 1: fails the new golden gad7-assessment ($.entry[0].resource.valueQuantity.value: golden 9, actual 10). - M4 ECG symptomsStatus read as notSet: fails the new sourceEvidenceReadsTheSample. - M5 effective time truncated to whole seconds: fails exporter-deployment-own-heart-rate (9b2e2d54). - M6 percent rounded to one decimal: fails convertsFromAnotherUnit (oxygen saturation: "7" for "7.000000000000001"). Tests: - HealthKitECGEvidenceValidatorTests.sourceEvidenceReadsTheSample: the public record path's ecgSourceEvidence on a stored HKElectrocardiogram (new StoredSampleFixtures.electrocardiogram: KVC on _privateClassification, _symptomsStatus and _averageHeartRate, read back or fail; HealthKit keeps the classification under a private numbering, 4 reads back as atrialFibrillation): type, bounds, zone, classification, symptoms status, average rate, algorithm version, and no count or frequency for unset voltages. - classificationsStateTheGuideCodes: every HKElectrocardiogram. Classification against the guide's closed code system (ig-pin healthkit/input/fsh/terminology.fsh:87-94), an independent oracle. - Golden gad7-assessment (observations group, sequence 15): an HKGAD7Assessment HealthKit scores 9; a supported type no golden covered. - HealthKitUnitBindingTests.convertsFromAnotherUnit: degF body temperature, miles, a percent fraction and mmol/L glucose, each pinned to its exact wire lexeme and code (37.00000000000006 Cel, 1609.344 m, 7.000000000000001 %, 99.08573400002975 mg/dL). Track 3's FX-F4-percent changes the percent row as an enumerated delta. - userEnteredECGMarksEveryOutput: an ECG whose metadata says it was user entered states manual entry on the waveform and on its average heart rate. Source (finding 9): the ECG's average-heart-rate child took its entry method from HealthKitECGSourceEvidence.wasUserEntered while the primary took it from SourceFacts (the sample's metadata); both read HKMetadataKeyWasUserEntered in production, but the evidence seam could make them disagree. The field is deleted and HealthKitAssembly.graph states the sample's own entry method on every output it assembles (documents take no manual-entry link, so they are unaffected). Output unchanged: all 53 goldens regenerate byte-identical, and HealthKitAssembly.outputRevision stays 2. Mutation proof for the new test of the source change: stating the entry method on outputs[0] only fails userEnteredECGMarksEveryOutput ("8867-4 states no manual entry"). Unmutated: 279 total, 277 passed, 2 skipped. Output diff: none. New golden gad7-assessment with its G17 row (assembler 1, healthKit 2, no bump); outlines.json only gains its entry. Gates: GroveHealthKitFHIR macOS 279 total, 277 passed, 2 skipped; swiftlint --strict: no findings; reuse lint: compliant. Co-Authored-By: Claude Opus 5.5 --- .../HealthKitAssembly.swift | 5 +- .../HealthKitConverter+ECGCore.swift | 6 +- .../HealthKitECGGraphInput.swift | 1 - .../ConformanceFixtureTests.swift | 3 +- .../GoldenGraphCases+Documents.swift | 3 +- .../GoldenGraphCases.swift | 9 + .../GoldenOutputRevisionTests.swift | 3 +- .../HealthKitECGEvidenceValidatorTests.swift | 95 ++++- .../HealthKitUnitBindingTests.swift | 36 ++ .../Resources/Goldens/gad7-assessment.json | 338 ++++++++++++++++++ .../Resources/Goldens/outlines.json | 49 +++ .../StoredSampleFixtures.swift | 22 ++ 12 files changed, 557 insertions(+), 13 deletions(-) create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/gad7-assessment.json diff --git a/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift b/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift index 1a297d96c..5ee091401 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift @@ -137,7 +137,10 @@ struct HealthKitAssembly: Sendable { let facts = try SourceFacts(sample, options: request.options) var outputs = outputs outputs[0].clearIdentifiers = facts.nativeIdentifiers - outputs[0].wasUserEntered = facts.wasUserEntered + // One record states one entry method: the sample's own metadata decides it for every output it yields. + for index in outputs.indices { + outputs[index].wasUserEntered = facts.wasUserEntered + } // A writer-record identity travels only with its version, and only an Observation carries the version // extension; a document states neither, though the pair is still validated. if case .observation = outputs[0].resource { diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+ECGCore.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+ECGCore.swift index 584f06558..7fd48390e 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+ECGCore.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter+ECGCore.swift @@ -50,8 +50,7 @@ extension HealthKitConverter { numberOfVoltageMeasurements: ecg.numberOfVoltageMeasurements, averageHeartRate: ecg.averageHeartRate?.doubleValue(for: .count().unitDivided(by: .minute())), samplingFrequency: ecg.samplingFrequency?.doubleValue(for: .hertz()), - algorithmVersion: (ecg.metadata?[HKMetadataKeyAppleECGAlgorithmVersion] as? NSNumber)?.intValue, - wasUserEntered: (ecg.metadata?[HKMetadataKeyWasUserEntered] as? Bool) == true + algorithmVersion: (ecg.metadata?[HKMetadataKeyAppleECGAlgorithmVersion] as? NSNumber)?.intValue ) } @@ -110,8 +109,7 @@ extension HealthKitConverter { return ExchangeOutputDraft( role: "average-heart-rate", resource: .observation(try averageHeartRateObservation(value: averageHeartRate, effective: effective, input: input)), - derivedFromPrimary: true, - wasUserEntered: input.source.wasUserEntered + derivedFromPrimary: true ) } diff --git a/Sources/GroveHealthKitFHIR/HealthKitECGGraphInput.swift b/Sources/GroveHealthKitFHIR/HealthKitECGGraphInput.swift index 2755f923f..d77ec0fa5 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitECGGraphInput.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitECGGraphInput.swift @@ -43,7 +43,6 @@ struct HealthKitECGSourceEvidence: Sendable { let averageHeartRate: Double? let samplingFrequency: Double? let algorithmVersion: Int? - let wasUserEntered: Bool } #endif diff --git a/Tests/GroveHealthKitFHIRTests/ConformanceFixtureTests.swift b/Tests/GroveHealthKitFHIRTests/ConformanceFixtureTests.swift index 94d85e14c..467c00487 100644 --- a/Tests/GroveHealthKitFHIRTests/ConformanceFixtureTests.swift +++ b/Tests/GroveHealthKitFHIRTests/ConformanceFixtureTests.swift @@ -410,8 +410,7 @@ struct ConformanceFixtureTests { numberOfVoltageMeasurements: 4, averageHeartRate: 72, samplingFrequency: 500, - algorithmVersion: HKAppleECGAlgorithmVersion.version2.rawValue, - wasUserEntered: false + algorithmVersion: HKAppleECGAlgorithmVersion.version2.rawValue ) let ecgWaveform = try HealthKitECGEvidenceValidator.validateWaveform( reportedCount: ecgSource.numberOfVoltageMeasurements, diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift index c7d517572..e45198c85 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift @@ -223,8 +223,7 @@ extension GoldenCase { numberOfVoltageMeasurements: 4, averageHeartRate: 72, samplingFrequency: 500, - algorithmVersion: HKAppleECGAlgorithmVersion.version2.rawValue, - wasUserEntered: false + algorithmVersion: HKAppleECGAlgorithmVersion.version2.rawValue ) let waveform = try HealthKitECGEvidenceValidator.validateWaveform( reportedCount: source.numberOfVoltageMeasurements, diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift index 0b5a0ed8c..0e901e24b 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift @@ -117,6 +117,15 @@ extension GoldenCase { StoredSampleFixtures.stored(GoldenFixtures.workout(withEvents: true), uuid: GoldenFixtures.uuid(14)), sequence: sequence ) + }, + // HealthKit scores the answers itself: 0 + 1 + 2 + 3 + 0 + 1 + 2. + GoldenCase("gad7-assessment", sequence: 15) { sequence in + let assessment = HKGAD7Assessment( + date: GoldenFixtures.sampleStart, + answers: [.notAtAll, .severalDays, .moreThanHalfTheDays, .nearlyEveryDay, .notAtAll, .severalDays, .moreThanHalfTheDays], + metadata: GoldenFixtures.timeZoneMetadata + ) + return try GoldenFixtures.convert(StoredSampleFixtures.stored(assessment, uuid: GoldenFixtures.uuid(15)), sequence: sequence) } ] diff --git a/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift b/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift index 13af68bea..e7486a3fc 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift @@ -60,6 +60,7 @@ struct GoldenOutputRevisionTests { GoldenRevision("exporter-deployment-own-heart-rate", digest: "lJKVrYY2oi58qD26E7Z__PClm6845IZNkkcqeiEj3Z4", assembler: 1, healthKit: 2), GoldenRevision("exporter-deployment-retraction", digest: "Cc_UaCTn-Mo0fTPXqL9sLghqSmfjEUFHr7vwCOvM55o", assembler: 1, healthKit: 2), GoldenRevision("exporter-deployment-state-of-mind", digest: "u0OjTBrTx1KQ6gHHOWmBDmgBkzKeCAWaijDQ0Aqccno", assembler: 1, healthKit: 2), + GoldenRevision("gad7-assessment", digest: "TdgtYWLW0Z6nYvWn6IyNsAssPbn0cuLRlqFng1pOq_c", assembler: 1, healthKit: 2), GoldenRevision("gateway-application-role", digest: "z4GLZX9z_-CYLMxzF6l78eLQXXDu_vCV6gHzIRVouYY", assembler: 1, healthKit: 2), GoldenRevision("gateway-role", digest: "6cz0Bpd-k9mt_HFFY8xyRT3dkjpDMjI8WnqlyMlGgO8", assembler: 1, healthKit: 2), GoldenRevision("heart-rate-device-without-unit-token", digest: "gKIE0MA3n8uoEIiPTWI-TJOBDAD1osZVz6C0sWLibk8", assembler: 1, healthKit: 1), @@ -72,7 +73,7 @@ struct GoldenOutputRevisionTests { GoldenRevision("heartbeat-series", digest: "fB3bdqSnBH2vJxBfzQQDFFeItPoT6Bs8Yom7uFbYS98", assembler: 1, healthKit: 2), GoldenRevision("insulin-delivery-bolus", digest: "fCw3-HgNHCW_r1bQ8bY5WiGz52iekzNbJ0-AKZp59yc", assembler: 1, healthKit: 1), GoldenRevision("native-identifier-disclosure", digest: "d0cEPkdGfs7W8CYbUpS-GDKoc64jN21WjgkWSibIAAM", assembler: 1, healthKit: 2), - GoldenRevision("outlines", digest: "8v5brDMbczGBPTCqVDSNiKrYocHE3iBFv1A1APzYDAk", assembler: 1, healthKit: 2), + GoldenRevision("outlines", digest: "a9ICIi7H0-ITVka39jDQ5WJoVaDm4XekGxKB6ZSbVqA", assembler: 1, healthKit: 2), GoldenRevision("repository-ids-on-every-node", digest: "wnO8sPt82cYYd4m50n4tycbEXWdgvNRlKjQItQI6n4Y", assembler: 1, healthKit: 1), GoldenRevision("retraction-blood-pressure", digest: "x4muVgyjqh8AfgVGhaS55MeMVmxJ58UR0hsghhedkEA", assembler: 1, healthKit: 1), GoldenRevision("retraction-electrocardiogram", digest: "JJIp4J2S4Vr0CX-d1fi3IqAmyNzuzSz4fyrF-gbrkgM", assembler: 1, healthKit: 1), diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitECGEvidenceValidatorTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitECGEvidenceValidatorTests.swift index 808f3795e..8dd7f8c97 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitECGEvidenceValidatorTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitECGEvidenceValidatorTests.swift @@ -115,6 +115,98 @@ struct HealthKitECGEvidenceValidatorTests { } } + /// The facts the public record path reads off an `HKElectrocardiogram` beside its voltages, field by field. + @Test("An ECG's source evidence states the sample's own classification, symptoms, rate, algorithm and zone") + func sourceEvidenceReadsTheSample() throws { + let start = GoldenFixtures.sampleStart + let shape = StoredSampleFixtures.SeriesShape( + uuid: GoldenFixtures.uuid(0xC0), + start: start, + end: start.addingTimeInterval(30), + device: GoldenFixtures.watch, + metadata: [HKMetadataKeyTimeZone: GoldenFixtures.timeZone, HKMetadataKeyAppleECGAlgorithmVersion: HKAppleECGAlgorithmVersion.version2.rawValue], + writer: GoldenFixtures.foreignWriter + ) + let ecg = try StoredSampleFixtures.electrocardiogram( + shape: shape, + reading: (privateClassification: 4, classification: .atrialFibrillation), + symptomsStatus: .present, + averageHeartRate: HKQuantity(unit: GoldenFixtures.beatsPerMinute, doubleValue: 112) + ) + let evidence = try HealthKitConverter.ecgSourceEvidence(ecg) + #expect(evidence.sourceTypeIdentifier == HealthKitContract.electrocardiogramSourceTypeIdentifier) + #expect(evidence.startDate == start) + #expect(evidence.endDate == start.addingTimeInterval(30)) + #expect(evidence.timeZone.identifier == GoldenFixtures.timeZone) + #expect(evidence.classification == .atrialFibrillation) + #expect(evidence.symptomsStatus == .present) + #expect(evidence.averageHeartRate == 112) + #expect(evidence.algorithmVersion == HKAppleECGAlgorithmVersion.version2.rawValue) + // Unset voltages report no measurements and no sampling frequency. + #expect(evidence.numberOfVoltageMeasurements == 0) + #expect(evidence.samplingFrequency == nil) + } + + /// Every HealthKit classification states its code of the guide's closed code system + /// (healthkit `terminology.fsh`, `HealthKitECGClassificationCS`). + @Test(arguments: [ + (HKElectrocardiogram.Classification.notSet, "notSet"), + (.sinusRhythm, "sinusRhythm"), + (.atrialFibrillation, "atrialFibrillation"), + (.inconclusiveLowHeartRate, "inconclusiveLowHeartRate"), + (.inconclusiveHighHeartRate, "inconclusiveHighHeartRate"), + (.inconclusivePoorReading, "inconclusivePoorReading"), + (.inconclusiveOther, "inconclusiveOther"), + (.unrecognized, "unrecognized") + ]) + func classificationsStateTheGuideCodes(_ classification: HKElectrocardiogram.Classification, _ code: String) throws { + let (_, evidence) = try GoldenCase.electrocardiogramEvidence(uuid: 0xC1, symptomsPresent: false) + let source = evidence.source + let observation = try HealthKitConverter.ecgObservation(input: HealthKitECGObservationInput( + source: HealthKitECGSourceEvidence( + sourceTypeIdentifier: source.sourceTypeIdentifier, + startDate: source.startDate, + endDate: source.endDate, + timeZone: source.timeZone, + classification: classification, + symptomsStatus: source.symptomsStatus, + numberOfVoltageMeasurements: source.numberOfVoltageMeasurements, + averageHeartRate: source.averageHeartRate, + samplingFrequency: source.samplingFrequency, + algorithmVersion: source.algorithmVersion + ), + waveform: evidence.waveform, + symptomOutputIdentifiers: [] + )) + #expect(observation.interpretation?.first?.coding?.map { $0.code?.value?.string } == [code]) + } + + /// One record states one entry method: the ECG's own metadata marks its waveform and its average heart rate alike. + @Test("A user-entered ECG states manual entry on the waveform and on its average heart rate") + func userEnteredECGMarksEveryOutput() throws { + let start = GoldenFixtures.sampleStart + let ecg = try StoredSampleFixtures.seriesSample( + HKElectrocardiogram.self, + sampleType: HKObjectType.electrocardiogramType(), + shape: StoredSampleFixtures.SeriesShape( + uuid: GoldenFixtures.uuid(0xC2), + start: start, + end: start.addingTimeInterval(30), + device: GoldenFixtures.watch, + metadata: [HKMetadataKeyTimeZone: GoldenFixtures.timeZone, HKMetadataKeyWasUserEntered: true], + writer: GoldenFixtures.foreignWriter + ) + ) + let (_, evidence) = try GoldenCase.electrocardiogramEvidence(uuid: 0xC2, symptomsPresent: false) + let conversion = try HealthKitConverter.convertECG(ecg, evidence: evidence, symptoms: [], context: HealthKitConversionContext(), symptomContexts: []) + let observations = conversion.bundle.entry?.compactMap { $0.resource?.get(if: Observation.self) } ?? [] + #expect(observations.count == 2) + for observation in observations { + let methods = observation.extension?.filter { $0.url == Canonicals.recordingMethod } ?? [] + #expect(methods.count == 1, "\(observation.code.coding?.first?.code?.value?.string ?? "") states no manual entry") + } + } + @Test( "Incomplete, contradictory, or nonuniform ECG evidence fails closed", arguments: [ @@ -255,8 +347,7 @@ struct HealthKitECGEvidenceValidatorTests { numberOfVoltageMeasurements: Self.validPoints.count, averageHeartRate: nil, samplingFrequency: 500, - algorithmVersion: nil, - wasUserEntered: false + algorithmVersion: nil ) let waveform = try HealthKitECGEvidenceValidator.validateWaveform( reportedCount: Self.validPoints.count, diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitUnitBindingTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitUnitBindingTests.swift index 7168e7d98..c889e62eb 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitUnitBindingTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitUnitBindingTests.swift @@ -9,12 +9,26 @@ #if canImport(HealthKit) import Foundation +@testable import GroveFHIRContract import GroveHealthKit @testable import GroveHealthKitFHIR import HealthKit import Testing +/// A sample HealthKit holds in a unit other than its contract's, and the `valueQuantity` the graph states for it. +struct UnitConversionCase: CustomTestStringConvertible, Sendable { + let type: HKQuantityTypeIdentifier + let unit: HKUnit + let value: Double + /// The decimal lexeme on the wire, exactly. + let lexeme: String + let code: String + + var testDescription: String { "\(value) \(unit.unitString) \(type.rawValue)" } +} + + /// The published UCUM-to-HealthKit correspondence. /// /// HealthKit cannot parse UCUM, so a consumer holding a contract's unit has no way to derive the @@ -63,6 +77,28 @@ struct HealthKitUnitBindingTests { } } + /// The converter reads a value in its contract's unit whatever unit HealthKit holds it in. The wire lexeme is + /// pinned exactly, binary noise included, so any change to the arithmetic is a visible, deliberate delta. + @Test(arguments: [ + UnitConversionCase(type: .bodyTemperature, unit: .degreeFahrenheit(), value: 98.6, lexeme: "37.00000000000006", code: "Cel"), + UnitConversionCase(type: .distanceWalkingRunning, unit: .mile(), value: 1, lexeme: "1609.344", code: "m"), + UnitConversionCase(type: .oxygenSaturation, unit: .percent(), value: 0.07, lexeme: "7.000000000000001", code: "%"), + UnitConversionCase( + type: .bloodGlucose, + unit: HKUnit.moleUnit(with: .milli, molarMass: HKUnitMolarMassBloodGlucose).unitDivided(by: .liter()), + value: 5.5, + lexeme: "99.08573400002975", + code: "mg/dL" + ) + ]) + func convertsFromAnotherUnit(_ conversion: UnitConversionCase) throws { + let sample = try GoldenFixtures.quantity(conversion.type, HKQuantity(unit: conversion.unit, doubleValue: conversion.value), uuid: GoldenFixtures.uuid(0xC8)) + let graph = try HealthKitConverter().convert(sample, context: GoldenFixtures.context(sequence: 900)).graph + let quantity = try LosslessJSONValue(parsing: graph.json)["entry"]?.elements?.first?["resource"]?["valueQuantity"] + #expect(quantity?["value"] == .number(conversion.lexeme)) + #expect(quantity?["code"]?.text == conversion.code) + } + /// One spelling never names two different HealthKit units. The reverse does not hold — every /// annotation unit is `count` — which is why no inverse lookup is published. @Test diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/gad7-assessment.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/gad7-assessment.json new file mode 100644 index 000000000..1b5fc3d5a --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/gad7-assessment.json @@ -0,0 +1,338 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:6aGEDo03PxFRQYOmR-9IVMGiToG6XRA00vDN_2NbrEM" + } + } + ], + "fullUrl" : "urn:uuid:bff0e639-7bb0-5df1-9cf7-43d77faa49b6", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "code" : { + "coding" : [ + { + "code" : "70274-6", + "display" : "Generalized anxiety disorder 7 item (GAD-7) total score [Reported.PHQ]", + "system" : "http://loinc.org" + } + ] + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKScoredAssessmentTypeIdentifierGAD7" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:h_uR84DR74tNFvCv4-gZlenKozqpGIwtZGLcyTdGunU" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:6aGEDo03PxFRQYOmR-9IVMGiToG6XRA00vDN_2NbrEM" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-gad7-assessment" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "{score}", + "system" : "http://unitsofmeasure.org", + "unit" : "score", + "value" : 9 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:ofbnkJcqk6YeV6vgDeOfnMvel2ywJn1Xthh-13KZcOc" + } + } + ], + "fullUrl" : "urn:uuid:aa662c8b-8157-53a8-b48d-0b44316b88d0", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:ofbnkJcqk6YeV6vgDeOfnMvel2ywJn1Xthh-13KZcOc" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:da2BrCNkBpArVSLDFGJ7V7DBhM2WsHvNVw-rIsldIcI" + } + } + ], + "fullUrl" : "urn:uuid:ed5c7ca9-d14f-5ddf-870d-b02d155af5b0", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:da2BrCNkBpArVSLDFGJ7V7DBhM2WsHvNVw-rIsldIcI" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:aa662c8b-8157-53a8-b48d-0b44316b88d0" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:QRpjFT0HLp5v8iuv278MFZ8agRpdgc4FZ91tPMeThGo" + } + } + ], + "fullUrl" : "urn:uuid:e0f85170-2536-55ac-9129-d7cbb435e9d2", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:ed5c7ca9-d14f-5ddf-870d-b02d155af5b0" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:h_uR84DR74tNFvCv4-gZlenKozqpGIwtZGLcyTdGunU" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:bff0e639-7bb0-5df1-9cf7-43d77faa49b6" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:15" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json index 7ce49e904..2016b1ea5 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json @@ -1119,6 +1119,55 @@ ] }, + "gad7-assessment" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:bff0e639-7bb0-5df1-9cf7-43d77faa49b6", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:h_uR84DR74tNFvCv4-gZlenKozqpGIwtZGLcyTdGunU", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:6aGEDo03PxFRQYOmR-9IVMGiToG6XRA00vDN_2NbrEM" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:aa662c8b-8157-53a8-b48d-0b44316b88d0", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:ofbnkJcqk6YeV6vgDeOfnMvel2ywJn1Xthh-13KZcOc" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:ed5c7ca9-d14f-5ddf-870d-b02d155af5b0", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:da2BrCNkBpArVSLDFGJ7V7DBhM2WsHvNVw-rIsldIcI", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:e0f85170-2536-55ac-9129-d7cbb435e9d2", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, "gateway-application-role" : { "entries" : [ { diff --git a/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift b/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift index 9b717abd7..2de7317bd 100644 --- a/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift +++ b/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift @@ -128,6 +128,28 @@ enum StoredSampleFixtures { return sample } + /// An `HKElectrocardiogram` reading `shape`'s facts, its classification, symptoms status and average heart rate. + /// Its voltages are HealthKit's private storage and stay unset, so it reports no measurement count and no sampling + /// frequency. HealthKit keeps the classification under a private numbering: `reading` names that number and the + /// public classification it must read back as, and the fixture fails unless every value reads back. + static func electrocardiogram( + shape: SeriesShape, + reading: (privateClassification: Int, classification: HKElectrocardiogram.Classification), + symptomsStatus: HKElectrocardiogram.SymptomsStatus, + averageHeartRate: HKQuantity + ) throws -> HKElectrocardiogram { + let ecg = try seriesSample(HKElectrocardiogram.self, sampleType: HKObjectType.electrocardiogramType(), shape: shape) + try write(NSNumber(value: reading.privateClassification), to: "privateClassification", of: ecg) + try write(NSNumber(value: symptomsStatus.rawValue), to: "symptomsStatus", of: ecg) + try write(averageHeartRate, to: "averageHeartRate", of: ecg) + guard ecg.classification == reading.classification, + ecg.symptomsStatus == symptomsStatus, + ecg.averageHeartRate == averageHeartRate else { + throw FixtureError.keyNotHonored(key: "privateClassification/symptomsStatus/averageHeartRate", class: String(describing: HKElectrocardiogram.self)) + } + return ecg + } + #if !os(watchOS) /// An `HKClinicalRecord` carrying `resource` as the provider's FHIR resource, the way a fetched record carries it; /// HealthKit offers no initializer for either class. Fails unless the record reads every value back. From 3511df762ac3af28f2be320e0fe0cec96400b5a0 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 14:51:00 +0200 Subject: [PATCH 028/220] Add the Envelope Fixes' Spec Tests and Validate Their Shapes in the HL7 Lane Fix-round step G3, audit ledger section 5 confirmed findings 1 (the specs' merge gates and regression tests were not added; F11 and F7 could be removed with the suite green; the workout Observation never met the HL7 validator) and 6 (gatewayForOwnWrites without a build is undocumented and untested), section 1 finding 10 (the workout golden has a bare context); G2 leftover: no conformance fixture carried a Provenance author. At 1c2f2a7c the audit's removals still passed everything: weakening the F11 reverse check (`guard governs else { continue }`) and reverting the F7 retraction instants, the clamp and DocumentReference.date (FHIRModels' DateTime(utc:)/Instant(utc:) again) each left 279/277 green. Tests: - F11 T1-T4 (new AdapterProvenanceGraphTests, ungated): a golden edited as a plain JSON object and re-validated through ExchangeGraph(validating:): HealthKit outputs under the mobile, SensorKit and providers Provenance report adapter-provenance-graph @ Bundle.entry; under the Health Connect Provenance data-origin-agent @ Provenance.entity[0].agent (the graph rule does not pre-empt it); a HealthKit Provenance also targeting a source-neutral output of its record reports @ Provenance.target, the same output claiming the adapter is accepted; a Patient claiming healthkit-observation reports mobile-exchange.unclassified @ Bundle. Every expectation was computed by running the pinned kit's exchange_bundle_diagnostics on the same edits (ig-pin, read-only, PYTHONDONTWRITEBYTECODE=1) and equals the F11 spec's. - F11 T5 (gated ExchangeGraphCorpusTests): ExchangeGraph.adapterConversionClaims equals catalog/profile-claims.json adapterConversionProvenanceClaims in order, profile and target set (healthkit 119, health-connect 6, providers 4, sensorkit 13). - F1: GoldenGraphTests.workoutRetractionIsExact (the catalog states workout|single, and the retraction's targets are exactly the outputs the addition emitted); HealthKitFHIRExporterTests.workoutExportAndRetraction (one Observation exported, the retraction targets exactly its session). New golden workout-session-context (observations group, sequence 16): the session under a study, a gateway application, manual entry and its recording watch, so every link a workout takes is pinned in bytes. - F7 (ExchangeEnvelopeFixTests): retractionInstantsAreMilliseconds (period start .0004 -> 22:30:00Z, end .9996 carries into 23:30:01Z, recorded and Bundle.timestamp .2514 -> .251Z, an instant .2516 -> .252Z, a start of .distantPast clamped to 0001-01-01T00:00:00Z) and documentDateIsMilliseconds. - F3 negatives and finding 6: sameBuildIsExact, HealthKitAssembly.isSameBuild over the exact build (true) and revision "41", nil, " ", "42 ", a foreign bundle and a converter without a build whose version equals the revision (all false). - F2: writerEqualToAnUnnamedGatewayIsItsOwnSnapshot: a heartbeat series under a gateway application whose token equals the classified writer's carries the writer as its own snapshot (name from HKSourceRevision, parent the writer host, repository id w-1) and as the Provenance author; on an Observation, which names the gateway, the same writer is the gateway's entry and the gateway extension references it. Finding 6 decision: documented, not refused. Under gatewayForOwnWrites an application without a build is merely the assembler, which the guide always admits (omission, mapping.md:132); the role compares the build the event froze, so a configuration-time check on the live producer could not guarantee the role either, and a refusal would add a public error case. ApplicationDevice(bundle:) always states CFBundleVersion. The RolePolicy doc now states the F3 A3 rule (no build, no revision version or another build: assembler; build reuse caveat). HL7 conformance lane (ConformanceFixtureTests): - `workout` from the guide's workout semantic vector (running, 17:00-17:45 -07:00, one lap withheld, the watch): the F1 merge gate. - `heart-rate-classified-writer`: a foreign application classified as one, with its writer Device, writer host and Provenance author. - The goldens no fixture covers: workout-session and every shape this step added (workout-session-context, writer-non-ascii-name, gad7-assessment, the exporter goldens), written as golden-.json. Left out: exporter-deployment-state-of-mind: the HL7 validator rejects any negative valence against the pinned guide's own healthkit-state-of-mind-value-domain-1 (value >= -1 and <= 1): probe valences -0.25 and -1 fail, 0 and 0.25 pass, an IG defect. Running every golden through the lane also showed insulin-delivery-bolus fails on HKInsulinDeliveryReason, a code the guide's healthkit-metadata-key CodeSystem lacks (pre-existing; not added). - The exporter deployment goldens move their disclosed-UUID system from https://study.example.org/fhir/NamingSystem/healthkit-store to https://grovealliance.org/fhir/testing/identifiers/native-healthkit-record, because the HL7 validator refuses example URLs: the only change in those six files (one identifier system each; ECG child has none) and in their outlines. A fixture input change of goldens added in 9b2e2d54, no converter output change, so their G17 rows keep healthKit 2. Mutation proof (each applied alone, full GroveHealthKitFHIRTests on macOS, then reverted; unmutated: 287 total, 285 passed, 2 skipped): - F11 weakened (`guard governs else { continue }`): fails reportsWhatTheKitReports (the mobile Provenance vector is accepted). - F7, each reverted alone: the instant occurrence (.251600027Z), the period end (.999599933Z), the start (.000400066Z), recorded (.251399993Z) fail retractionInstantsAreMilliseconds; DocumentReference.date fails documentDateIsMilliseconds; the clamp alone removed refuses the .distantPast start (invalidInstant). - the catalog retracts a workout segment besides the session: fails workoutRetractionIsExact, workoutExportAndRetraction and the retraction-workout golden. - isSameBuild falls back to the version when no build is stated: fails sameBuildIsExact. - the writer never shares a converter snapshot: fails writerEqualToAnUnnamedGatewayIsItsOwnSnapshot (and four golden tests); documents naming the gateway again: fails it and documentGraphsOmitTheGatewayApplication. Output diff: none. New golden workout-session-context with its G17 row (assembler 1, healthKit 2); the exporter deployment goldens change only as listed; all other goldens byte-identical. Gates: GroveHealthKitFHIR macOS 287 total, 285 passed, 2 skipped; swiftlint --strict: no findings; reuse lint: compliant; Scripts/validate-fhir-conformance.sh healthkit against g3-ig, a clone of the G2 scratchpad copy of ig-pin with mobile, sensor and healthkit built (GROVE_FHIR_REF its commit): "Validated 42 producer resource(s) against FHIR R4", "OK - all healthkit resources conform to their declared R4 profiles", contract generator and semantic-vector checks clean. Co-Authored-By: Claude Opus 5.5 --- .../HealthKitFHIRExporter+Options.swift | 10 +- .../AdapterProvenanceGraphTests.swift | 148 ++++ .../ConformanceFixtureTests.swift | 64 +- .../ExchangeEnvelopeFixTests.swift | 104 +++ .../ExchangeGraphCorpusTests.swift | 19 + .../GoldenGraphCases+Exporter.swift | 4 +- .../GoldenGraphCases.swift | 9 + .../GoldenGraphFixtures.swift | 7 +- .../GoldenGraphTests.swift | 16 + .../GoldenOutputRevisionTests.swift | 15 +- .../HealthKitFHIRExporterTests.swift | 15 + .../exporter-deployment-blood-pressure.json | 2 +- ...-deployment-electrocardiogram-symptom.json | 2 +- ...exporter-deployment-electrocardiogram.json | 2 +- .../exporter-deployment-own-heart-rate.json | 2 +- .../exporter-deployment-retraction.json | 2 +- .../exporter-deployment-state-of-mind.json | 2 +- .../Resources/Goldens/outlines.json | 114 ++- .../Goldens/workout-session-context.json | 707 ++++++++++++++++++ 19 files changed, 1217 insertions(+), 27 deletions(-) create mode 100644 Tests/GroveHealthKitFHIRTests/AdapterProvenanceGraphTests.swift create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/workout-session-context.json diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift index aa4eef488..8b7df70e3 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift @@ -108,9 +108,13 @@ extension HealthKitFHIRExporter { public enum RolePolicy: Hashable, Sendable { /// The application assembled graphs from records it did not mediate. case assembler - /// Samples this application wrote itself in the build it runs (the source bundle identifier equals the - /// application's and the revision's version equals its build) are stated as mediated by it; every other - /// sample is merely assembled. + /// Samples this application wrote in the build it states (the source's bundle identifier equals the + /// application's, and `HKSourceRevision.version`, the source's `CFBundleVersion`, equals + /// `ApplicationDevice.build`) are stated as mediated by it. Every other sample is merely assembled: one + /// written by another build, one whose revision states no version, and every sample when the application + /// states no build, which `ApplicationDevice(bundle:)` always reads from `CFBundleVersion`. The comparison + /// uses the application the event froze. iOS lets an app reuse a build number in another release; an app + /// that does so names the current release for such a sample. case gatewayForOwnWrites /// The converting application mediated every measurement. case gateway diff --git a/Tests/GroveHealthKitFHIRTests/AdapterProvenanceGraphTests.swift b/Tests/GroveHealthKitFHIRTests/AdapterProvenanceGraphTests.swift new file mode 100644 index 000000000..834d330a2 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/AdapterProvenanceGraphTests.swift @@ -0,0 +1,148 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +@testable import GroveFHIRContract +@testable import GroveHealthKitFHIR +import Testing + + +/// Re-validation reports what the pinned kit reports for a golden it was handed with one fault: the kit's results for +/// these vectors were computed by running `exchange_bundle_diagnostics` on the same edited JSON (ig-pin, read-only). +/// +/// `mobile-exchange.adapter-provenance-graph` (spec F11): every adapter output must sit under its adapter's conversion +/// Provenance, which targets exactly the adapter's outputs of its source record; the kit decides this last, by claim. +@Suite +struct AdapterProvenanceGraphTests { + /// One edited golden and what re-validating it reports. + struct Vector: CustomTestStringConvertible, Sendable { + let testDescription: String + let golden: String + /// `nil` when the edited graph is accepted. + let expected: (code: String, location: String)? + let edit: @Sendable (inout [String: Any]) throws -> Void + + init( + _ testDescription: String, + golden: String, + expected: (code: String, location: String)?, + edit: @escaping @Sendable (inout [String: Any]) throws -> Void + ) { + self.testDescription = testDescription + self.golden = golden + self.expected = expected + self.edit = edit + } + } + + private static let provenanceProfiles = [ + "mobile": "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-conversion-provenance", + "sensorkit": "https://grovealliance.org/fhir/sensorkit/StructureDefinition/sensorkit-conversion-provenance", + "providers": "https://grovealliance.org/fhir/providers/StructureDefinition/providers-conversion-provenance", + "health-connect": "https://grovealliance.org/fhir/health-connect/StructureDefinition/health-connect-conversion-provenance" + ] + + private static let graphRule = "mobile-exchange.adapter-provenance-graph" + + static let vectors: [Vector] = [ + // T1: HealthKit outputs under a source-neutral or another adapter's Provenance. + governing("mobile", expected: (graphRule, "Bundle.entry")), + governing("sensorkit", expected: (graphRule, "Bundle.entry")), + governing("providers", expected: (graphRule, "Bundle.entry")), + // T2: the moved graph rule does not pre-empt the Health Connect data-origin check. + governing("health-connect", expected: ("health-connect-provenance.data-origin-agent", "Provenance.entity[0].agent")), + // T3: a HealthKit Provenance that also targets a source-neutral output of its record. + Vector("a target outside the adapter's outputs", golden: "heart-rate-minimal", expected: (graphRule, "Provenance.target")) { bundle in + try appendOutput(to: &bundle, adapterClaimed: false) + }, + Vector("a second adapter output of the record, targeted", golden: "heart-rate-minimal", expected: nil) { bundle in + try appendOutput(to: &bundle, adapterClaimed: true) + }, + // T4: an entry that is no output claims an adapter output profile; the kit fails it without a rule. + Vector("a Patient claiming an adapter output profile", golden: "bundled-patient-subject", expected: ("mobile-exchange.unclassified", "Bundle")) { bundle in + try edit(&bundle, entry: 1) { entry in + try edit(&entry, member: "resource") { resource in + resource["meta"] = ["profile": ["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]] + } + } + } + ] + + /// heart-rate-minimal with its Provenance claiming `adapter`'s conversion profile instead of HealthKit's. + private static func governing(_ adapter: String, expected: (code: String, location: String)) -> Vector { + Vector("HealthKit outputs under the \(adapter) Provenance", golden: "heart-rate-minimal", expected: expected) { bundle in + try edit(&bundle, entry: 3) { entry in + try edit(&entry, member: "resource") { resource in + resource["meta"] = ["profile": [provenanceProfiles[adapter] ?? ""]] + } + } + } + } + + /// Adds a copy of entry 0 as a second output of the same record, under a new source-output identity and the + /// fullUrl it keys, claiming the HealthKit adapter or only its source-neutral profile, and targets it. + private static func appendOutput(to bundle: inout [String: Any], adapterClaimed: Bool) throws { + var entries = try #require(bundle["entry"] as? [[String: Any]]) + var output = entries[0] + let identity = try #require(entries[0]["extension"] as? [[String: Any]]).first?["valueIdentifier"] as? [String: Any] + let system = try #require(identity?["system"] as? String) + let value = "v0:test:1:" + String(repeating: "A", count: 43) + let fullURL = try RoledIdentifier(identifier: BusinessIdentifier(system: IdentifierSystem(system), value: value), role: .sourceOutput).fullURLString + output["fullUrl"] = fullURL + try edit(&output, member: "extension", index: 0) { node in + try edit(&node, member: "valueIdentifier") { $0["value"] = value } + } + try edit(&output, member: "resource") { resource in + try edit(&resource, member: "identifier", index: 1) { $0["value"] = value } + if !adapterClaimed { + resource["meta"] = ["profile": ["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate"]] + resource["extension"] = nil + } + } + entries.append(output) + try edit(&entries[3], member: "resource") { provenance in + let targets = try #require(provenance["target"] as? [[String: Any]]) + provenance["target"] = targets + [["reference": fullURL]] + } + bundle["entry"] = entries + } + + private static func edit(_ bundle: inout [String: Any], entry index: Int, _ change: (inout [String: Any]) throws -> Void) throws { + try edit(&bundle, member: "entry", index: index, change) + } + + private static func edit(_ object: inout [String: Any], member: String, _ change: (inout [String: Any]) throws -> Void) throws { + var value = try #require(object[member] as? [String: Any]) + try change(&value) + object[member] = value + } + + private static func edit(_ object: inout [String: Any], member: String, index: Int, _ change: (inout [String: Any]) throws -> Void) throws { + var array = try #require(object[member] as? [[String: Any]]) + try change(&array[index]) + object[member] = array + } + + @Test(arguments: AdapterProvenanceGraphTests.vectors) + func reportsWhatTheKitReports(_ vector: Vector) throws { + var bundle = try #require(try JSONSerialization.jsonObject(with: GoldenStore.data(named: vector.golden)) as? [String: Any]) + try vector.edit(&bundle) + let json = try JSONSerialization.data(withJSONObject: bundle, options: [.sortedKeys, .withoutEscapingSlashes]) + do { + _ = try ExchangeGraph(validating: json, kind: .active) + #expect(vector.expected == nil, "accepted, the kit reports \(String(describing: vector.expected))") + } catch { + let diagnostic = error.diagnostic + #expect(vector.expected?.code == diagnostic.code && vector.expected?.location == diagnostic.location, "reported \(diagnostic.code) @ \(diagnostic.location)") + } + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/ConformanceFixtureTests.swift b/Tests/GroveHealthKitFHIRTests/ConformanceFixtureTests.swift index 467c00487..404c1d8bf 100644 --- a/Tests/GroveHealthKitFHIRTests/ConformanceFixtureTests.swift +++ b/Tests/GroveHealthKitFHIRTests/ConformanceFixtureTests.swift @@ -81,6 +81,25 @@ struct ConformanceFixtureTests { ) } + /// The goldens whose shapes no fixture above covers: the workout session and every shape the fix round added. + /// `exporter-deployment-state-of-mind` is left out: its negative valence fails the pinned guide's own + /// `healthkit-state-of-mind-value-domain-1` in the HL7 validator, which rejects every negative value although the + /// invariant admits -1 through 1, an IG defect. + private static let validatedGoldens: Set = [ + "workout-session", + "workout-session-context", + "writer-non-ascii-name", + "gad7-assessment", + "exporter-default-apple-watch-heart-rate", + "exporter-deployment-own-heart-rate", + "exporter-deployment-electrocardiogram", + "exporter-deployment-electrocardiogram-symptom", + "exporter-deployment-blood-pressure", + "exporter-deployment-retraction", + "exporter-clinical-record-r4", + "exporter-clinical-record-dstu2" + ] + @Test func writeConformanceFixtures() throws { let encoder = JSONEncoder() @@ -305,6 +324,41 @@ struct ConformanceFixtureTests { metadata: [HKMetadataKeySexualActivityProtectionUsed: true] ) + // Spec F1: the workout session, its one output, from the guide's workout vector; its lap is withheld. + let workout = try vector("workout") + guard case .codeableConcept("running") = workout.result else { + throw FixtureError.unexpectedResult(workout.id) + } + let workoutDates = try dates(workout) + try add("workout", HKWorkout( + activityType: .running, + start: workoutDates.start, + end: workoutDates.end, + workoutEvents: [HKWorkoutEvent(type: .lap, dateInterval: DateInterval(start: workoutDates.start, duration: 900), metadata: nil)], + totalEnergyBurned: HKQuantity(unit: .kilocalorie(), doubleValue: 420), + totalDistance: HKQuantity(unit: .meter(), doubleValue: 7_500), + device: Self.device, + metadata: [HKMetadataKeyTimeZone: Self.sourceTimeZoneIdentifier] + )) + + // A source the caller classifies as an application: its writer Device, its host and the Provenance author. + let writerContext = HealthKitConversionContext( + subject: Self.subject, + converter: context.converter, + graphIdentifierSystem: context.graphIdentifierSystem, + writer: .application, + converterWasGateway: true, + conversionInstant: contextTime + ) + fixtures["heart-rate-classified-writer"] = try converter.convert( + StoredSampleFixtures.stored( + quantity(.heartRate, .count().unitDivided(by: .minute()), 64, effective: .dateTime("2026-08-20T08:25:00-07:00")), + uuid: UUID(uuidString: "6C4B1D1E-0000-4000-8000-0000000000F1") ?? UUID(), + writer: GoldenFixtures.foreignWriter + ), + context: writerContext + ).bundle + let mindfulness = try vector("mindfulness-session") try add("mindfulness-session", category( .mindfulSession, @@ -519,7 +573,12 @@ struct ConformanceFixtureTests { try encoder.encode(ecgConversion.bundle).write( to: directory.appendingPathComponent("electrocardiogram.json") ) - #expect(fixtures.count == 27) + let validatedGoldens = Self.validatedGoldens.subtracting(GoldenCase.unavailableHere) + #expect(Set(GoldenCase.all.map(\.name)).isSuperset(of: validatedGoldens)) + for goldenCase in GoldenCase.all where validatedGoldens.contains(goldenCase.name) { + try goldenCase.output().graph.json.write(to: directory.appendingPathComponent("golden-\(goldenCase.name).json")) + } + #expect(fixtures.count == 29) let emittedVectorIDs = Set(fixtures.keys).intersection(Set(MobileSemanticVectorFixtures.all.map(\.id))) #expect(emittedVectorIDs == Set([ "active-energy", @@ -544,7 +603,8 @@ struct ConformanceFixtureTests { "resting-heart-rate", "sexual-activity", "sleep-stage", - "step-count" + "step-count", + "workout" ])) } diff --git a/Tests/GroveHealthKitFHIRTests/ExchangeEnvelopeFixTests.swift b/Tests/GroveHealthKitFHIRTests/ExchangeEnvelopeFixTests.swift index 921aad8c8..02301ccec 100644 --- a/Tests/GroveHealthKitFHIRTests/ExchangeEnvelopeFixTests.swift +++ b/Tests/GroveHealthKitFHIRTests/ExchangeEnvelopeFixTests.swift @@ -18,6 +18,19 @@ import Testing /// The envelope rules the pinned guide states and the first assembler missed: what a document graph /// carries, how event instants are written, and which deletions a route policy lets the exporter retract. +/// One revision and converter build, and whether the converter wrote the sample in the build it runs. +struct SameBuildCase: CustomTestStringConvertible, Sendable { + let revisionVersion: String? + let build: String? + let expected: Bool + var bundleIdentifier = ApplicationDevice.test.bundleIdentifier + + var testDescription: String { + "revision \(revisionVersion.map { "'\($0)'" } ?? "nil") of \(bundleIdentifier), build \(build ?? "nil")" + } +} + + @Suite struct ExchangeEnvelopeFixTests { private static let base = ExchangeEventContext.test() @@ -102,6 +115,47 @@ struct ExchangeEnvelopeFixTests { #expect(occurred.value?.description == "2026-08-17T23:30:00.251Z") } + @Test("A retraction states its bounds and its recording in UTC at millisecond precision, and a start before year 1 as year 1") + @available(*, deprecated, message: "Exercises the deprecated converter's retraction, which takes any instant") + func retractionInstantsAreMilliseconds() throws { + let context = HealthKitConversionContext(event: .test(conversionInstant: Date(timeIntervalSince1970: 1_787_009_400.2514))) + func provenance(_ occurred: RetractionOccurrence) throws -> (bundle: ModelsR4.Bundle, provenance: Provenance) { + let record = HealthKitSourceRecord(uuid: GoldenFixtures.uuid(96), type: .heartRate) + let bundle = try HealthKitConverter().retraction(for: record, context: context, occurred: occurred).graph.bundle + return (bundle, try #require(bundle.entry?.compactMap { $0.resource?.get(if: Provenance.self) }.first)) + } + let bounded = try provenance(.period( + start: Date(timeIntervalSince1970: 1_787_005_800.0004), + end: Date(timeIntervalSince1970: 1_787_009_400.9996) + )) + guard case .period(let period)? = bounded.provenance.occurred else { + Issue.record("A retraction with bounds occurs over a period") + return + } + #expect(period.start?.value?.description == "2026-08-17T22:30:00Z") + #expect(period.end?.value?.description == "2026-08-17T23:30:01Z", "rounding carries into the next second") + #expect(bounded.provenance.recorded.value?.description == "2026-08-17T23:30:00.251Z") + #expect(bounded.bundle.timestamp?.value?.description == "2026-08-17T23:30:00.251Z") + guard case .dateTime(let instant)? = try provenance(.instant(Date(timeIntervalSince1970: 1_787_009_400.2516))).provenance.occurred else { + Issue.record("A retraction at an instant occurs at that instant") + return + } + #expect(instant.value?.description == "2026-08-17T23:30:00.252Z") + guard case .period(let clamped)? = try provenance(.period(start: .distantPast, end: GoldenFixtures.conversionInstant)).provenance.occurred else { + Issue.record("A retraction with bounds occurs over a period") + return + } + #expect(clamped.start?.value?.description == "0001-01-01T00:00:00Z") + } + + @Test("A document's date is the event instant in UTC at millisecond precision") + @available(*, deprecated, message: "Exercises the deprecated converter's document path") + func documentDateIsMilliseconds() throws { + let context = HealthKitConversionContext(event: .test(conversionInstant: Date(timeIntervalSince1970: 1_787_009_400.2514))) + let conversion = try HealthKitConverter().convert(try Self.heartbeatSeries(uuid: 97), context: context) + #expect(conversion.document.date?.value?.description == "2026-08-17T23:30:00.251Z") + } + @Test("A route deletion is retracted only while routes are disclosed") func routeRetractionFollowsTheRoutePolicy() throws { let deletion = HealthKitFHIRExporter.Deletion( @@ -137,6 +191,56 @@ struct ExchangeEnvelopeFixTests { #expect(statesGateway(exports[0])) #expect(!statesGateway(exports[1])) } + + /// Spec F3: only the exact build matches; HealthKit copies the source's `CFBundleVersion` into the revision. + @Test(arguments: [ + SameBuildCase(revisionVersion: "42", build: "42", expected: true), + SameBuildCase(revisionVersion: "41", build: "42", expected: false), + SameBuildCase(revisionVersion: nil, build: "42", expected: false), + SameBuildCase(revisionVersion: " ", build: "42", expected: false), + SameBuildCase(revisionVersion: "42 ", build: "42", expected: false), + SameBuildCase(revisionVersion: "42", build: "42", expected: false, bundleIdentifier: "org.example.writer"), + // An application stating no build is never matched, even when its version equals the revision's. + SameBuildCase(revisionVersion: "42", build: nil, expected: false) + ]) + func sameBuildIsExact(_ testCase: SameBuildCase) throws { + var writer = GoldenFixtures.selfWriter(revisionVersion: testCase.revisionVersion) + writer.bundleIdentifier = testCase.bundleIdentifier + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(98), writer: writer) + let application = GoldenFixtures.selfConverter(version: testCase.build == nil ? "42" : "1.2.3", build: testCase.build) + #expect(HealthKitAssembly.isSameBuild(sample.sourceRevision, as: application) == testCase.expected) + } + + /// Spec F2: a gateway no output names is no snapshot, so a writer whose token equals it gets its own entries. + @Test("A writer equal to a gateway no output names is its own snapshot and author, beside its own host") + @available(*, deprecated, message: "Exercises the deprecated converter's document path") + func writerEqualToAnUnnamedGatewayIsItsOwnSnapshot() throws { + var inputs = GoldenFixtures.Inputs.applicationWriter + inputs.converterRole = .gatewayApplication(.test(name: "Cuff Companion", bundleIdentifier: "org.example.writer", version: "42")) + var documentInputs = inputs + documentInputs.repositoryIDs = [.writer: try RepositoryID("w-1")] + let document = try HealthKitConverter().convert(try Self.heartbeatSeries(uuid: 99), context: GoldenFixtures.context(sequence: 99, documentInputs)) + let writer = try #require(document.writer) + let writerHost = try #require(document.identifiers.writerHostSnapshot) + #expect(writer.deviceName?.first?.name.value?.string == "Example Writer") + #expect(writer.parent?.reference?.value?.string == (try writerHost.fullURLString)) + #expect(writer.id?.value?.string == "w-1") + let author = document.provenance.entity?.first?.agent?.first { $0.type?.coding?.first?.code?.value?.string == "author" } + #expect(author?.who.reference?.value?.string == (try document.identifiers.writerSnapshot?.fullURLString)) + // On an Observation, which names the gateway, the same writer is the gateway's entry. + let observation = try HealthKitConverter().convert( + GoldenCase.attributedHeartRate(uuid: 0x99, writer: GoldenFixtures.foreignWriter), + context: GoldenFixtures.context(sequence: 100_099, inputs) + ) + #expect(observation.writer?.deviceName?.first?.name.value?.string == "Cuff Companion") + #expect(observation.identifiers.writerHostSnapshot == nil) + let gateway = observation.observation.extension?.first { $0.url == Canonicals.gatewayDevice } + guard case .reference(let reference)? = gateway?.value else { + Issue.record("The Observation names its gateway") + return + } + #expect(reference.reference?.value?.string == (try observation.identifiers.writerSnapshot?.fullURLString)) + } } #endif diff --git a/Tests/GroveHealthKitFHIRTests/ExchangeGraphCorpusTests.swift b/Tests/GroveHealthKitFHIRTests/ExchangeGraphCorpusTests.swift index c2d6ad1f8..321f7dcf2 100644 --- a/Tests/GroveHealthKitFHIRTests/ExchangeGraphCorpusTests.swift +++ b/Tests/GroveHealthKitFHIRTests/ExchangeGraphCorpusTests.swift @@ -179,6 +179,25 @@ struct ExchangeGraphCorpusTests { } } + /// T5 of spec F11: the adapter-provenance-graph rule walks the claims in the pinned catalog's order, and the + /// first failing claim decides the reported location, so the generated table must keep that order and sets. + @Test("The adapter conversion claims are the pinned catalog's, in its order") + func adapterConversionClaimsMatchTheCatalog() throws { + struct Catalog: Decodable { + struct Claim: Decodable { + let profile: String + let targetAdapterProfiles: [String] + } + + let adapterConversionProvenanceClaims: [Claim] + } + + let catalogURL = protocolCatalogURL.deletingLastPathComponent().appendingPathComponent("profile-claims.json") + let claims = try JSONDecoder().decode(Catalog.self, from: Data(contentsOf: catalogURL)).adapterConversionProvenanceClaims + #expect(ExchangeGraph.adapterConversionClaims.map(\.provenanceProfile) == claims.map(\.profile)) + #expect(ExchangeGraph.adapterConversionClaims.map(\.outputProfiles) == claims.map { Set($0.targetAdapterProfiles) }) + } + @Test("Every shared mutation reports the exact structured Grove diagnostic") func reportsExactSharedCorpusDiagnostics() throws { let corpusURL = corpusDirectory.appendingPathComponent("corpus.json") diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Exporter.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Exporter.swift index 6de2ff418..12e7baee5 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Exporter.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Exporter.swift @@ -20,6 +20,8 @@ enum ExporterGolden { /// The deployment's own application, in the build it runs. static let deploymentApplication = ApplicationDevice.test(name: "Grove Study", bundleIdentifier: "org.example.study", version: "4.1.0", build: "412") static let deploymentStudies: [StudyEnrollment] = [.test("study-a")] + /// The deployment's own system for the HealthKit UUID; not an example URL, so the HL7 validator accepts it. + static let deploymentNativeIdentifierSystem: IdentifierSystem = "https://grovealliance.org/fhir/testing/identifiers/native-healthkit-record" /// A sample the deployment's own application wrote in the build it runs. static let deploymentWriter = StoredSampleFixtures.Writer( @@ -43,7 +45,7 @@ enum ExporterGolden { /// bundle identifier the one source classified as an application, and every other option at its default. static var deploymentOptions: HealthKitFHIRExporter.Options { var options = HealthKitFHIRExporter.Options() - options.nativeIdentifier = .authorized(system: GoldenFixtures.nativeIdentifierSystem) + options.nativeIdentifier = .authorized(system: deploymentNativeIdentifierSystem) options.legacyBundleID = .healthKitUUID options.role = .gatewayForOwnWrites options.writer = .applications([deploymentApplication.bundleIdentifier]) diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift index 0e901e24b..4bf1a327a 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases.swift @@ -126,6 +126,15 @@ extension GoldenCase { metadata: GoldenFixtures.timeZoneMetadata ) return try GoldenFixtures.convert(StoredSampleFixtures.stored(assessment, uuid: GoldenFixtures.uuid(15)), sequence: sequence) + }, + // The session under every envelope link it takes (spec F1): a study, a gateway application, manual entry + // and the watch that recorded it. + GoldenCase("workout-session-context", sequence: 16) { sequence in + var inputs = GoldenFixtures.Inputs() + inputs.studies = [.test("study-a")] + inputs.converterRole = .gatewayApplication(.test(name: "Cuff Companion", bundleIdentifier: "com.example.cuff", version: "3.1")) + let workout = GoldenFixtures.workout(withEvents: false, device: GoldenFixtures.watch, userEntered: true) + return try GoldenFixtures.convert(StoredSampleFixtures.stored(workout, uuid: GoldenFixtures.uuid(16)), sequence: sequence, inputs) } ] diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift index d09dfb7f6..bcf792fc2 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift @@ -253,8 +253,8 @@ enum GoldenFixtures { } /// A one-hour run in Berlin with 640 kcal and 10 km; with events, a pause, a resume, eight laps and two - /// segments, which the converter withholds. - static func workout(withEvents: Bool) -> HKWorkout { + /// segments, which the converter withholds. `device` is the recorder; `userEntered` marks it entered by hand. + static func workout(withEvents: Bool, device: HKDevice? = nil, userEntered: Bool = false) -> HKWorkout { let begin = Date(timeIntervalSince1970: 1_786_000_000) var events: [HKWorkoutEvent] = [] if withEvents { @@ -280,7 +280,8 @@ enum GoldenFixtures { workoutEvents: events.isEmpty ? nil : events, totalEnergyBurned: HKQuantity(unit: .kilocalorie(), doubleValue: 640), totalDistance: HKQuantity(unit: .meter(), doubleValue: 10_000), - metadata: [HKMetadataKeyTimeZone: "Europe/Berlin"] + device: device, + metadata: userEntered ? [HKMetadataKeyTimeZone: "Europe/Berlin", HKMetadataKeyWasUserEntered: true] : [HKMetadataKeyTimeZone: "Europe/Berlin"] ) } diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift index 369ae9899..52dee1643 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift @@ -242,6 +242,22 @@ struct GoldenGraphTests { #expect(provenance.target.count == 1) } + /// F1: a workout's retraction names exactly the outputs its addition emitted, recomputed from its type and UUID. + @Test + func workoutRetractionIsExact() throws { + #expect(HealthKitCatalog.outputs(for: .workout).map { "\($0.role)|\($0.discriminator)" } == ["workout|single"]) + let workout = try StoredSampleFixtures.stored(GoldenFixtures.workout(withEvents: true), uuid: GoldenFixtures.uuid(0xA2)) + let conversion = try HealthKitConverter().convert(workout, context: GoldenFixtures.context(sequence: 202)) + let retraction = try HealthKitConverter().retraction( + for: HealthKitSourceRecord(uuid: workout.uuid, type: .workout), + context: GoldenFixtures.context(sequence: 203), + occurred: .instant(GoldenFixtures.conversionInstant) + ) + let provenance = try #require(retraction.graph.bundle.entry?.compactMap { $0.resource?.get(if: Provenance.self) }.first) + let emitted = ([conversion.identifiers.primaryOutput] + conversion.identifiers.childOutputs).map(\.identifier.value) + #expect(provenance.target.compactMap { $0.identifier?.value?.value?.string } == emitted) + } + /// A writer classified as an application whose bundle identifier is not one is a refusal; a writer with a blank /// name is merely no writer (`writer-blank-name-with-sync-identity` pins that graph). @Test diff --git a/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift b/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift index e7486a3fc..73151d975 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift @@ -54,12 +54,12 @@ struct GoldenOutputRevisionTests { GoldenRevision("exporter-clinical-record-dstu2", digest: "9U3i57-PMHal6ADvTYRUUuffIO_5pDB2kB20U_nzX1g", assembler: 1, healthKit: 2), GoldenRevision("exporter-clinical-record-r4", digest: "fLwKd9npbWfEncV49t-W0T8TUVGFh5pjZaHMVZfv7kg", assembler: 1, healthKit: 2), GoldenRevision("exporter-default-apple-watch-heart-rate", digest: "InGqi5S9GIR-Xqk9CltCUCExrkoBf4tOnBJguLfbVUk", assembler: 1, healthKit: 2), - GoldenRevision("exporter-deployment-blood-pressure", digest: "4rj5hMKeT-anu8BUghWFNOjRoifJo9cRyM7e4HQjl5k", assembler: 1, healthKit: 2), - GoldenRevision("exporter-deployment-electrocardiogram", digest: "fgz_sJLYrq34lVEFTVH4VlD1CyCtn0KELtFnoqlxYCw", assembler: 1, healthKit: 2), - GoldenRevision("exporter-deployment-electrocardiogram-symptom", digest: "uAPam_vM-x6yIOufY56CvWiydx6EdDJ-n7yVjZAE1kM", assembler: 1, healthKit: 2), - GoldenRevision("exporter-deployment-own-heart-rate", digest: "lJKVrYY2oi58qD26E7Z__PClm6845IZNkkcqeiEj3Z4", assembler: 1, healthKit: 2), - GoldenRevision("exporter-deployment-retraction", digest: "Cc_UaCTn-Mo0fTPXqL9sLghqSmfjEUFHr7vwCOvM55o", assembler: 1, healthKit: 2), - GoldenRevision("exporter-deployment-state-of-mind", digest: "u0OjTBrTx1KQ6gHHOWmBDmgBkzKeCAWaijDQ0Aqccno", assembler: 1, healthKit: 2), + GoldenRevision("exporter-deployment-blood-pressure", digest: "Aq5rL8UXjvLTTQsgor4mTWY-5VIutrJamQ7chv_uRyI", assembler: 1, healthKit: 2), + GoldenRevision("exporter-deployment-electrocardiogram", digest: "3GLqhvS12BlRLJ9ETVd1qV5crlxD8TPRCvCCW1tFDUA", assembler: 1, healthKit: 2), + GoldenRevision("exporter-deployment-electrocardiogram-symptom", digest: "W-CoOf3DL1ofEW_sGj2nCqAi51UX9lV8t70zVrisgdk", assembler: 1, healthKit: 2), + GoldenRevision("exporter-deployment-own-heart-rate", digest: "QtWugQ9lY0GvQ3XF6nidsocOq12Sr4bNwJfqsTQHdXc", assembler: 1, healthKit: 2), + GoldenRevision("exporter-deployment-retraction", digest: "U0OhQ98ldoCEGN0VyAITsm7MXSUoLGSztHpQhRJ2TwQ", assembler: 1, healthKit: 2), + GoldenRevision("exporter-deployment-state-of-mind", digest: "CZ5sA-fjkCqwnp178-8iATtDuHjzGDMxUItbwKHJxxI", assembler: 1, healthKit: 2), GoldenRevision("gad7-assessment", digest: "TdgtYWLW0Z6nYvWn6IyNsAssPbn0cuLRlqFng1pOq_c", assembler: 1, healthKit: 2), GoldenRevision("gateway-application-role", digest: "z4GLZX9z_-CYLMxzF6l78eLQXXDu_vCV6gHzIRVouYY", assembler: 1, healthKit: 2), GoldenRevision("gateway-role", digest: "6cz0Bpd-k9mt_HFFY8xyRT3dkjpDMjI8WnqlyMlGgO8", assembler: 1, healthKit: 2), @@ -73,7 +73,7 @@ struct GoldenOutputRevisionTests { GoldenRevision("heartbeat-series", digest: "fB3bdqSnBH2vJxBfzQQDFFeItPoT6Bs8Yom7uFbYS98", assembler: 1, healthKit: 2), GoldenRevision("insulin-delivery-bolus", digest: "fCw3-HgNHCW_r1bQ8bY5WiGz52iekzNbJ0-AKZp59yc", assembler: 1, healthKit: 1), GoldenRevision("native-identifier-disclosure", digest: "d0cEPkdGfs7W8CYbUpS-GDKoc64jN21WjgkWSibIAAM", assembler: 1, healthKit: 2), - GoldenRevision("outlines", digest: "a9ICIi7H0-ITVka39jDQ5WJoVaDm4XekGxKB6ZSbVqA", assembler: 1, healthKit: 2), + GoldenRevision("outlines", digest: "IO5I6QbUUxWkCk1WNeGrYpAP2KE-jxpeSajPwSH5dn0", assembler: 1, healthKit: 2), GoldenRevision("repository-ids-on-every-node", digest: "wnO8sPt82cYYd4m50n4tycbEXWdgvNRlKjQItQI6n4Y", assembler: 1, healthKit: 1), GoldenRevision("retraction-blood-pressure", digest: "x4muVgyjqh8AfgVGhaS55MeMVmxJ58UR0hsghhedkEA", assembler: 1, healthKit: 1), GoldenRevision("retraction-electrocardiogram", digest: "JJIp4J2S4Vr0CX-d1fi3IqAmyNzuzSz4fyrF-gbrkgM", assembler: 1, healthKit: 1), @@ -88,6 +88,7 @@ struct GoldenOutputRevisionTests { GoldenRevision("udi-disclosure", digest: "WzH-xG6V54w8RejhkvpOo7L__Xi3J6qZc1giw8-ps4M", assembler: 1, healthKit: 2), GoldenRevision("workout-route", digest: "PBv3pI8sKIsHZAKmYK_9eTawK56ITbaCGS2miDe0Cxc", assembler: 1, healthKit: 2), GoldenRevision("workout-session", digest: "1JlAdaXFilr2KXrYdxEvZXAGjMUaSxFaJfiPpZuvGlE", assembler: 1, healthKit: 1), + GoldenRevision("workout-session-context", digest: "EvoLNOTHZrUcHlEFwZDa-ZJr5HyW-iB9C4pgyOb_S8E", assembler: 1, healthKit: 2), GoldenRevision("writer-blank-name-with-sync-identity", digest: "eGHwwHdaM8H_QqW2kRQqNcXBj-309dPxpqy3gkXnKNU", assembler: 1, healthKit: 1), GoldenRevision("writer-foreign-application", digest: "SaD46SDNVFB6NPQJmIBglAQpwczYwAKlQvSlLl8-d24", assembler: 1, healthKit: 1), GoldenRevision("writer-host-equals-converter-host", digest: "fGxbULDNVld5Ke8SXJEiEaHwi_W-3p2KTFpG7i6jQQs", assembler: 1, healthKit: 1), diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift index 2a87d4ac5..658a9d05f 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift @@ -255,6 +255,21 @@ struct HealthKitFHIRExporterTests { #expect(period.end != nil) } + @Test("F1: an exported workout is its session alone, and its retraction targets exactly that session") + func workoutExportAndRetraction() throws { + let exporter = try Self.exporter() + let workout = try StoredSampleFixtures.stored(GoldenFixtures.workout(withEvents: true), uuid: GoldenFixtures.uuid(0xA3)) + let (exports, _) = try Self.collect(exporter, [workout]) + let observations = try #require(exports.first?.graph?.bundle.entry?.compactMap { $0.resource?.get(if: Observation.self) }) + try #require(observations.count == 1) + let session = try #require(observations[0].identifier?.first { (try? RoledIdentifier($0).role) == .sourceOutput }?.value?.value?.string) + var retractions: [HealthKitFHIRExporter.Export] = [] + let deletion = HealthKitFHIRExporter.Deletion(uuid: workout.uuid, sourceType: .workout, deletedAfter: nil, detectedAt: GoldenFixtures.conversionInstant) + _ = try exporter.retract([deletion], at: GoldenFixtures.conversionInstant) { retractions.append($0) } + let provenance = try #require(retractions.first?.graph?.bundle.entry?.compactMap { $0.resource?.get(if: Provenance.self) }.first) + #expect(provenance.target.compactMap { $0.identifier?.value?.value?.string } == [session]) + } + @Test("An export shares one receipt; an error in the receiver ends the call with the reservations kept") func receiverErrorsPropagate() throws { struct Stop: Error {} diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-blood-pressure.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-blood-pressure.json index 738e399bd..65b3694aa 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-blood-pressure.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-blood-pressure.json @@ -125,7 +125,7 @@ "value" : "v0:test:1:8vqPK5IkIrDkwsqF0FS9IOi0M56-nZgPITlFTuY1UzI" }, { - "system" : "https://study.example.org/fhir/NamingSystem/healthkit-store", + "system" : "https://grovealliance.org/fhir/testing/identifiers/native-healthkit-record", "value" : "3a7e5c10-0000-4000-8000-0000000000b4" } ], diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-electrocardiogram-symptom.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-electrocardiogram-symptom.json index 13ec56278..b4ae53a6c 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-electrocardiogram-symptom.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-electrocardiogram-symptom.json @@ -91,7 +91,7 @@ "value" : "v0:test:1:K9V2p1LjBGEt7K_4B1pyE8qAjp8evO1PfZO0xd60Jvo" }, { - "system" : "https://study.example.org/fhir/NamingSystem/healthkit-store", + "system" : "https://grovealliance.org/fhir/testing/identifiers/native-healthkit-record", "value" : "3a7e5c10-0000-4000-8000-0000000000b3" } ], diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-electrocardiogram.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-electrocardiogram.json index df0c5d7f5..de20b7ea9 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-electrocardiogram.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-electrocardiogram.json @@ -127,7 +127,7 @@ "value" : "v0:test:1:OFv8xcXen2S9ewx-C_x6Kf_LK21ZvQR443wn4GQknhw" }, { - "system" : "https://study.example.org/fhir/NamingSystem/healthkit-store", + "system" : "https://grovealliance.org/fhir/testing/identifiers/native-healthkit-record", "value" : "3a7e5c10-0000-4000-8000-0000000000b2" } ], diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-own-heart-rate.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-own-heart-rate.json index 2a44ae9ad..b6c5aece8 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-own-heart-rate.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-own-heart-rate.json @@ -97,7 +97,7 @@ "value" : "v0:test:1:CR04mZJUxRK7xXGAagUV0xEWWmHxRoClZ6yg1Bw1i20" }, { - "system" : "https://study.example.org/fhir/NamingSystem/healthkit-store", + "system" : "https://grovealliance.org/fhir/testing/identifiers/native-healthkit-record", "value" : "3a7e5c10-0000-4000-8000-0000000000b1" } ], diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-retraction.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-retraction.json index 995bd7354..d5450b8d8 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-retraction.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-retraction.json @@ -97,7 +97,7 @@ { "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-retraction-target-native-identifier", "valueIdentifier" : { - "system" : "https://study.example.org/fhir/NamingSystem/healthkit-store", + "system" : "https://grovealliance.org/fhir/testing/identifiers/native-healthkit-record", "value" : "3a7e5c10-0000-4000-8000-0000000000b8" } } diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-state-of-mind.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-state-of-mind.json index 8e6db7412..4affd4776 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-state-of-mind.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-deployment-state-of-mind.json @@ -162,7 +162,7 @@ "value" : "v0:test:1:Kb32ohff3sFflnWGrREZSf1_z1RqyVDuTrYNztttbhU" }, { - "system" : "https://study.example.org/fhir/NamingSystem/healthkit-store", + "system" : "https://grovealliance.org/fhir/testing/identifiers/native-healthkit-record", "value" : "3a7e5c10-0000-4000-8000-0000000000b7" } ], diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json index 2016b1ea5..cc9d21eb3 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json @@ -628,7 +628,7 @@ "identifiers" : [ "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:DtsjmvTnOYCFDrfMTg47m8F_RadoyVJ4I_PXX9u2Wlc", "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:8vqPK5IkIrDkwsqF0FS9IOi0M56-nZgPITlFTuY1UzI", - "-|https://study.example.org/fhir/NamingSystem/healthkit-store|3a7e5c10-0000-4000-8000-0000000000b4" + "-|https://grovealliance.org/fhir/testing/identifiers/native-healthkit-record|3a7e5c10-0000-4000-8000-0000000000b4" ], "resourceType" : "Observation" }, @@ -722,7 +722,7 @@ "identifiers" : [ "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:Z0jDsNvEd05V7-ne3fOCDWvISewHM5tY7RU4djTJ6Sg", "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:OFv8xcXen2S9ewx-C_x6Kf_LK21ZvQR443wn4GQknhw", - "-|https://study.example.org/fhir/NamingSystem/healthkit-store|3a7e5c10-0000-4000-8000-0000000000b2" + "-|https://grovealliance.org/fhir/testing/identifiers/native-healthkit-record|3a7e5c10-0000-4000-8000-0000000000b2" ], "resourceType" : "Observation" }, @@ -826,7 +826,7 @@ "identifiers" : [ "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:fpa5kNlnUtj_xme3hPVThHDLGtoIHU5ngdpFiPze2lw", "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:K9V2p1LjBGEt7K_4B1pyE8qAjp8evO1PfZO0xd60Jvo", - "-|https://study.example.org/fhir/NamingSystem/healthkit-store|3a7e5c10-0000-4000-8000-0000000000b3" + "-|https://grovealliance.org/fhir/testing/identifiers/native-healthkit-record|3a7e5c10-0000-4000-8000-0000000000b3" ], "resourceType" : "Observation" }, @@ -919,7 +919,7 @@ "identifiers" : [ "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:KZGJ-PcDN04ZoVNJYRArjDpRHlUpuRqUxgeiOXceUKs", "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:CR04mZJUxRK7xXGAagUV0xEWWmHxRoClZ6yg1Bw1i20", - "-|https://study.example.org/fhir/NamingSystem/healthkit-store|3a7e5c10-0000-4000-8000-0000000000b1" + "-|https://grovealliance.org/fhir/testing/identifiers/native-healthkit-record|3a7e5c10-0000-4000-8000-0000000000b1" ], "resourceType" : "Observation" }, @@ -1049,7 +1049,7 @@ "identifiers" : [ "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:b_LSS9ukw4_W6ZJju_Zqey0ojqEWqiV75AuWYp1Swig", "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:Kb32ohff3sFflnWGrREZSf1_z1RqyVDuTrYNztttbhU", - "-|https://study.example.org/fhir/NamingSystem/healthkit-store|3a7e5c10-0000-4000-8000-0000000000b7" + "-|https://grovealliance.org/fhir/testing/identifiers/native-healthkit-record|3a7e5c10-0000-4000-8000-0000000000b7" ], "resourceType" : "Observation" }, @@ -2589,6 +2589,110 @@ ] }, + "workout-session-context" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-method", + "http://hl7.org/fhir/StructureDefinition/observation-gatewayDevice", + "http://hl7.org/fhir/StructureDefinition/workflow-researchStudy" + ], + "fullUrl" : "urn:uuid:fa48bae2-f21c-5b7b-8870-18d2cc38d552", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:Q-9Wabcy8_dCA5K4Pjy5_JKQLFzTqhEWRzagLKCABlU", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:3WpwxVd_vATaPvulIJx-Z7T21FR9hmvS3R4EEmvcWWk" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:7d9243ae-1cf4-5375-bcba-68d025e0419b", + "identifiers" : [ + "-|https://grovealliance.org/fhir/testing/identifiers/researchstudy|study-a" + ], + "resourceType" : "ResearchStudy" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:2f96f376-0522-5318-8918-bb98d1a508c6", + "identifiers" : [ + + ], + "resourceType" : "PlanDefinition" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:e641ad72-8e4c-58bf-8d5c-16722ae864fe", + "identifiers" : [ + "-|https://grovealliance.org/fhir/testing/identifiers/researchsubject|enrollment-study-a" + ], + "resourceType" : "ResearchSubject" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:08c5f54a-63db-51fa-9496-2fd9f7ac312b", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:khZX_eouckoXk5lkDVbMxNjdJSjYQtRZm1MoWw1PLrE", + "recording-device|https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1|v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:f62848b4-581c-5074-97a8-b8f3bc2a1c9f", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:vCCqhE446UberNzoi0pYArClfqOhPFDJIy-PjY5zOBA" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:a6223d61-2ba5-5765-84cb-91ae27b0d4b2", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:stCkfBljz56appfmxObdjjmUYxqtILAjZ0JaKNBGxZE", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:bc823eac-74a8-516c-8431-4a6c362c42e7", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:9UGF6H7bd1Dv1FctpTVMGIvxXaKEwespIladz6-T2Kc", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|com.example.cuff" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:192b846b-142d-50df-99b5-dbf0b8878650", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + + ] + }, "writer-blank-name-with-sync-identity" : { "entries" : [ { diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/workout-session-context.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/workout-session-context.json new file mode 100644 index 000000000..a6d78c802 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/workout-session-context.json @@ -0,0 +1,707 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:3WpwxVd_vATaPvulIJx-Z7T21FR9hmvS3R4EEmvcWWk" + } + } + ], + "fullUrl" : "urn:uuid:fa48bae2-f21c-5b7b-8870-18d2cc38d552", + "resource" : { + "code" : { + "coding" : [ + { + "code" : "workout", + "display" : "Workout session", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement" + } + ] + }, + "component" : [ + { + "code" : { + "coding" : [ + { + "code" : "active-duration", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic" + } + ] + }, + "valueQuantity" : { + "code" : "s", + "system" : "http://unitsofmeasure.org", + "unit" : "s", + "value" : 3600 + } + }, + { + "code" : { + "coding" : [ + { + "code" : "distance-sum", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic" + } + ] + }, + "valueQuantity" : { + "code" : "m", + "system" : "http://unitsofmeasure.org", + "unit" : "m", + "value" : 10000 + } + }, + { + "code" : { + "coding" : [ + { + "code" : "active-energy-sum", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic" + } + ] + }, + "valueQuantity" : { + "code" : "kcal", + "system" : "http://unitsofmeasure.org", + "unit" : "kcal", + "value" : 640 + } + } + ], + "device" : { + "reference" : "urn:uuid:08c5f54a-63db-51fa-9496-2fd9f7ac312b" + }, + "effectivePeriod" : { + "_end" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "Europe/Berlin" + } + ] + }, + "_start" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "Europe/Berlin" + } + ] + }, + "end" : "2026-08-06T10:06:40+02:00", + "start" : "2026-08-06T09:06:40+02:00" + }, + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKWorkoutTypeIdentifier" + }, + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-method", + "valueCoding" : { + "code" : "manual-entry", + "display" : "Manual entry", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-recording-method" + } + }, + { + "url" : "http://hl7.org/fhir/StructureDefinition/observation-gatewayDevice", + "valueReference" : { + "reference" : "urn:uuid:bc823eac-74a8-516c-8431-4a6c362c42e7" + } + }, + { + "url" : "http://hl7.org/fhir/StructureDefinition/workflow-researchStudy", + "valueReference" : { + "reference" : "urn:uuid:7d9243ae-1cf4-5375-bcba-68d025e0419b", + "type" : "ResearchStudy" + } + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Q-9Wabcy8_dCA5K4Pjy5_JKQLFzTqhEWRzagLKCABlU" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:3WpwxVd_vATaPvulIJx-Z7T21FR9hmvS3R4EEmvcWWk" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueCodeableConcept" : { + "coding" : [ + { + "code" : "running", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity" + }, + { + "code" : "running", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity" + } + ] + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:research-study:0:xjKJAqdvkwoGfGaF4UfAuXapWxRn_OPS82Hh0zyma28" + } + } + ], + "fullUrl" : "urn:uuid:7d9243ae-1cf4-5375-bcba-68d025e0419b", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/researchstudy", + "value" : "study-a" + } + ], + "protocol" : [ + { + "reference" : "urn:uuid:2f96f376-0522-5318-8918-bb98d1a508c6" + } + ], + "resourceType" : "ResearchStudy", + "status" : "active" + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:plan-definition:0:yG7AzMtaSK4GCEDjVGYWwZaOJ1FE66GUdUC30gP6tl8" + } + } + ], + "fullUrl" : "urn:uuid:2f96f376-0522-5318-8918-bb98d1a508c6", + "resource" : { + "resourceType" : "PlanDefinition", + "status" : "active", + "url" : "https://study.example.org/PlanDefinition/study-a", + "version" : "1" + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:research-subject:0:UP9EVY-CmBj2JRjGQMC6tOegqMMQZIN4QwPpqrismI0" + } + } + ], + "fullUrl" : "urn:uuid:e641ad72-8e4c-58bf-8d5c-16722ae864fe", + "resource" : { + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/researchsubject", + "value" : "enrollment-study-a" + } + ], + "individual" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "resourceType" : "ResearchSubject", + "status" : "on-study", + "study" : { + "reference" : "urn:uuid:7d9243ae-1cf4-5375-bcba-68d025e0419b" + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:khZX_eouckoXk5lkDVbMxNjdJSjYQtRZm1MoWw1PLrE" + } + } + ], + "fullUrl" : "urn:uuid:08c5f54a-63db-51fa-9496-2fd9f7ac312b", + "resource" : { + "deviceName" : [ + { + "name" : "Apple Watch", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:khZX_eouckoXk5lkDVbMxNjdJSjYQtRZm1MoWw1PLrE" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/recording-device/test/1", + "type" : { + "coding" : [ + { + "code" : "recording-device", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:7ceeJ-0nPsZ-N0AFDq-WIajkv78fYDH6-t7S9p6t1XY" + } + ], + "manufacturer" : "Apple Inc.", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-device" + ] + }, + "modelNumber" : "Watch7,12", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531974", + "display" : "MDC_ID_PROD_SPEC_HW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "Watch7,12" + }, + { + "type" : { + "coding" : [ + { + "code" : "531976", + "display" : "MDC_ID_PROD_SPEC_FW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + }, + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "26.2.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:vCCqhE446UberNzoi0pYArClfqOhPFDJIy-PjY5zOBA" + } + } + ], + "fullUrl" : "urn:uuid:f62848b4-581c-5074-97a8-b8f3bc2a1c9f", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:vCCqhE446UberNzoi0pYArClfqOhPFDJIy-PjY5zOBA" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:stCkfBljz56appfmxObdjjmUYxqtILAjZ0JaKNBGxZE" + } + } + ], + "fullUrl" : "urn:uuid:a6223d61-2ba5-5765-84cb-91ae27b0d4b2", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:stCkfBljz56appfmxObdjjmUYxqtILAjZ0JaKNBGxZE" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:f62848b4-581c-5074-97a8-b8f3bc2a1c9f" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:9UGF6H7bd1Dv1FctpTVMGIvxXaKEwespIladz6-T2Kc" + } + } + ], + "fullUrl" : "urn:uuid:bc823eac-74a8-516c-8431-4a6c362c42e7", + "resource" : { + "deviceName" : [ + { + "name" : "Cuff Companion", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:9UGF6H7bd1Dv1FctpTVMGIvxXaKEwespIladz6-T2Kc" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "com.example.cuff" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "3.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:lrfHN_ChHNwVgCEtJZycEFs7UUYsHNBIKDWtp-Cz4mA" + } + } + ], + "fullUrl" : "urn:uuid:192b846b-142d-50df-99b5-dbf0b8878650", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:a6223d61-2ba5-5765-84cb-91ae27b0d4b2" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:Q-9Wabcy8_dCA5K4Pjy5_JKQLFzTqhEWRzagLKCABlU" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:fa48bae2-f21c-5b7b-8870-18d2cc38d552" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:16" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file From 727f062c005bf84c8f3e128514f929a0cfd4aebb Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 15:01:49 +0200 Subject: [PATCH 029/220] Report the Kit's Diagnostics for Data Origins and Doubly Claimed Provenances Fix-round step G3, audit ledger section 5 confirmed finding 7 (Swift and the IG kit report different diagnostics for two invalid shapes). Grove's validator was the one that differed, and it also accepted what the kit refuses, so it is aligned to the pinned kit (ig-pin Scripts/producer_validation/profiles.py). - health-connect-provenance.data-origin-agent: Swift counted only the agents typed enterer, required just some identifier, and reported every fault at Provenance.entity[0].agent. The kit (profiles.py:663-707) requires exactly one agent on the source entity (else .agent), typed enterer and no other participant type, an identifier-only Device reference (else .agent[0].who), and an identifier under the Android package-name system with a non-blank value (else .agent[0].who.identifier). Swift now decides and locates it the same way, so an enterer beside an author, an author alone, or a package name under another system or blank is refused where the kit refuses it. - A Provenance claiming an adapter's conversion profile beside another profile: the kit refuses it without a rule in validate_adapter_conversion_provenance (profiles.py, before the profile-count rule), so it reports mobile-exchange.unclassified @ Bundle; Swift reported mobile-exchange.provenance-profile. The new validateAdapterProvenanceClaim reads meta.profile as written and requires an adapter conversion profile to be the only claim, before validateActiveProvenanceProfile. directProfiles now reads through the same writtenProfiles helper. No Grove producer writes a Health Connect Provenance or a second Provenance profile (the assembler states one), so wire output is unchanged; only re-validation verdicts and locations change, toward the kit's. Tests (AdapterProvenanceGraphTests, kit-computed expectations, same edits run through exchange_bundle_diagnostics read-only): - Health Connect Provenance over writer-foreign-application (its author agent): data-origin-agent @ .agent[0].who; an enterer under another system and one with a blank package name: @ .agent[0].who.identifier; an enterer and an author: @ .agent; an enterer referencing a Device: @ .agent[0].who; a complete data origin: passes the rule and the HealthKit outputs then fail adapter-provenance-graph @ Bundle.entry. - heart-rate-minimal's Provenance claiming the HealthKit and the mobile conversion profiles: mobile-exchange.unclassified @ Bundle. The agents reference the converter's own entry, so a vector has one fault: an unresolved reference is refused earlier by Swift's reference rule. Mutation proof (each applied alone, full GroveHealthKitFHIRTests on macOS, then reverted; unmutated: 287 total, 285 passed, 2 skipped): - validateAdapterProvenanceClaim not called: fails reportsWhatTheKitReports (reported mobile-exchange.provenance-profile @ Provenance.meta.profile). - a who fault located at .agent: fails it (reported @ Provenance.entity[0].agent). - any identifier system accepted: fails it (the wrong-system vector passes the rule and reports adapter-provenance-graph @ Bundle.entry). Output diff: none (goldens byte-identical). Gates: GroveHealthKitFHIR macOS 287 total, 285 passed, 2 skipped; GroveSensorKitFHIR 83/83; GroveQuestionnaire 260/260; GroveFHIR 103/103; GROVE_LOWERED_DEPLOYMENT_TARGETS=1 xcrun swift build --target GroveFHIRContract: Build complete (the manifest's "2 unhandled files" warning is pre-existing); swiftlint --strict: no findings; reuse lint: compliant. Co-Authored-By: Claude Opus 5.5 --- .../ExchangeGraph+Profiles.swift | 52 +++++++++++---- .../AdapterProvenanceGraphTests.swift | 66 +++++++++++++++++++ 2 files changed, 105 insertions(+), 13 deletions(-) diff --git a/Sources/GroveFHIRContract/ExchangeGraph+Profiles.swift b/Sources/GroveFHIRContract/ExchangeGraph+Profiles.swift index 0c25f5354..0027f3a4a 100644 --- a/Sources/GroveFHIRContract/ExchangeGraph+Profiles.swift +++ b/Sources/GroveFHIRContract/ExchangeGraph+Profiles.swift @@ -16,6 +16,9 @@ import ModelsR4 extension ExchangeGraph { + /// The system of the Android package name a Health Connect data origin is identified by (health-connect guide). + static let androidPackageNameSystem = "https://grovealliance.org/fhir/health-connect/NamingSystem/android-package-name" + /// Every adapter conversion claim in the pinned catalog's `adapterConversionProvenanceClaims` order, with the adapter /// output profiles its Provenance governs. The generator lists the source-neutral profile first, which has no targets. static let adapterConversionClaims: [(provenanceProfile: String, outputProfiles: Set)] = @@ -90,6 +93,7 @@ extension ExchangeGraph { rule: .mobileSupportQuestionnaireResponseProfile ) case .provenance(let provenance): + try validateAdapterProvenanceClaim(at: entryIndex, document: validationDocument) try validateActiveProvenanceProfile(provenance) return provenance default: @@ -208,6 +212,17 @@ extension ExchangeGraph { } } + /// A Provenance claiming an adapter's conversion profile claims it alone, exactly as written: the kit refuses any + /// other claim beside it without a rule (profiles.py, validate_adapter_conversion_provenance), so Grove reports + /// `mobile-exchange.unclassified`, before the profile-count rule. + static func validateAdapterProvenanceClaim(at index: Int, document: ValidationDocument) throws(ExchangeGraphError) { + let profiles = try writtenProfiles(at: index, document: document) + let claimed = adapterConversionClaims.filter { profiles.contains($0.provenanceProfile) } + guard claimed.isEmpty || (claimed.count == 1 && profiles == [claimed[0].provenanceProfile]) else { + throw .invalidEntries("An adapter conversion Provenance claims more than its adapter's profile") + } + } + static func validateActiveProvenanceProfile( _ provenance: Provenance ) throws(ExchangeGraphError) { @@ -292,30 +307,41 @@ extension ExchangeGraph { /// The entry resource's `meta.profile` exactly as written, read from the parsed Bundle as the kit reads it. private static func directProfiles(at index: Int, document: ValidationDocument) throws(ExchangeGraphError) -> Set { + Set(try writtenProfiles(at: index, document: document)) + } + + /// The entry resource's `meta.profile` exactly as written and in order, read from the parsed Bundle. + private static func writtenProfiles(at index: Int, document: ValidationDocument) throws(ExchangeGraphError) -> [String] { do { let object = try document.resourceObject(at: index) as? [String: Any] - return Set((object?["meta"] as? [String: Any])?["profile"] as? [String] ?? []) + return (object?["meta"] as? [String: Any])?["profile"] as? [String] ?? [] } catch { throw .invalidEntries(String(reflecting: type(of: error))) } } - /// A Health Connect conversion names its data origin as one identifier-only enterer Device agent. + /// A Health Connect conversion names its data origin as the source entity's one agent: typed enterer and nothing + /// else, an identifier-only Device reference to a non-blank Android package name. Each fault is located where + /// the kit locates it (profiles.py:663-707): the agent list, its `who`, or that reference's identifier. static func validateDataOriginAgent(_ provenance: Provenance) throws(ExchangeGraphError) { guard provenance.meta?.profile?.contains(Profile.healthConnectConversionProvenance) == true else { return } - let enterers = (provenance.entity?.first?.agent ?? []).filter { agent in - agent.type?.coding?.contains { - $0.system?.value?.url.absoluteString == participantSystem && $0.code?.value?.string == "enterer" - } == true - } - guard enterers.count == 1, - let who = enterers.first?.who, - who.reference == nil, - who.identifier != nil, - who.type?.value?.url.absoluteString == ResourceType.device.rawValue else { - throw diagnostic(.healthConnectProvenanceDataOriginAgent, location: "Provenance.entity[0].agent") + let location = "Provenance.entity[0].agent" + guard let agents = provenance.entity?.first?.agent, agents.count == 1, let agent = agents.first else { + throw diagnostic(.healthConnectProvenanceDataOriginAgent, location: location) + } + let participantCodes = (agent.type?.coding ?? []) + .filter { $0.system?.value?.url.absoluteString == participantSystem } + .map { $0.code?.value?.string } + guard participantCodes == ["enterer"], + agent.who.reference == nil, + agent.who.type?.value?.url.absoluteString == ResourceType.device.rawValue else { + throw diagnostic(.healthConnectProvenanceDataOriginAgent, location: location + "[0].who") + } + guard agent.who.identifier?.system?.value?.url.absoluteString == androidPackageNameSystem, + agent.who.identifier?.value?.value?.string.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == false else { + throw diagnostic(.healthConnectProvenanceDataOriginAgent, location: location + "[0].who.identifier") } } diff --git a/Tests/GroveHealthKitFHIRTests/AdapterProvenanceGraphTests.swift b/Tests/GroveHealthKitFHIRTests/AdapterProvenanceGraphTests.swift index 834d330a2..7bcd31077 100644 --- a/Tests/GroveHealthKitFHIRTests/AdapterProvenanceGraphTests.swift +++ b/Tests/GroveHealthKitFHIRTests/AdapterProvenanceGraphTests.swift @@ -72,9 +72,75 @@ struct AdapterProvenanceGraphTests { resource["meta"] = ["profile": ["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]] } } + }, + // A Provenance claiming an adapter's conversion profile beside another; the kit fails it without a rule. + Vector("a Provenance claiming two conversion profiles", golden: "heart-rate-minimal", expected: ("mobile-exchange.unclassified", "Bundle")) { bundle in + try edit(&bundle, entry: 3) { entry in + try edit(&entry, member: "resource") { resource in + let healthKit = "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + resource["meta"] = ["profile": [healthKit, provenanceProfiles["mobile"] ?? ""]] + } + } + } + ] + dataOriginVectors + + /// `health-connect-provenance.data-origin-agent`, located where the kit finds each fault (profiles.py:663-707). + static let dataOriginVectors: [Vector] = [ + dataOrigin("an author agent", golden: "writer-foreign-application", agents: nil, at: ".agent[0].who"), + dataOrigin("an enterer under another system", agents: { _ in [enterer(system: "https://grovealliance.org/fhir/testing/identifiers/package")] }, at: ".agent[0].who.identifier"), + dataOrigin("an enterer with a blank package name", agents: { _ in [enterer(value: " ")] }, at: ".agent[0].who.identifier"), + dataOrigin("an enterer and an author", agents: { converter in [enterer(), ["type": participant("author"), "who": ["reference": converter]]] }, at: ".agent"), + dataOrigin("an enterer referencing a Device", agents: { converter in [["type": participant("enterer"), "who": ["reference": converter, "type": "Device"]]] }, at: ".agent[0].who"), + // A complete data origin passes the rule; the HealthKit outputs then fail the graph rule. + Vector("a complete data origin over HealthKit outputs", golden: "heart-rate-minimal", expected: (graphRule, "Bundle.entry")) { bundle in + try governedByHealthConnect(&bundle) { _ in [enterer()] } } ] + private static func participant(_ code: String) -> [String: Any] { + ["coding": [["system": "http://terminology.hl7.org/CodeSystem/provenance-participant-type", "code": code]]] + } + + private static func enterer( + system: String = "https://grovealliance.org/fhir/health-connect/NamingSystem/android-package-name", + value: String = "com.example.scale" + ) -> [String: Any] { + ["type": participant("enterer"), "who": ["type": "Device", "identifier": ["system": system, "value": value]]] + } + + private static func dataOrigin( + _ description: String, + golden: String = "heart-rate-minimal", + agents: (@Sendable (_ converter: String) -> [[String: Any]])?, + at location: String + ) -> Vector { + let expected = ("health-connect-provenance.data-origin-agent", "Provenance.entity[0]" + location) + return Vector("Health Connect Provenance with \(description)", golden: golden, expected: expected) { bundle in + try governedByHealthConnect(&bundle, agents: agents) + } + } + + /// The graph's Provenance claiming Health Connect's conversion profile, its source entity naming the agents + /// `agents` builds from the converter's resolving reference, when given. + private static func governedByHealthConnect( + _ bundle: inout [String: Any], + agents: (@Sendable (_ converter: String) -> [[String: Any]])? + ) throws { + let entries = try #require(bundle["entry"] as? [[String: Any]]) + let index = try #require(entries.firstIndex { ($0["resource"] as? [String: Any])?["resourceType"] as? String == "Provenance" }) + try edit(&bundle, entry: index) { entry in + try edit(&entry, member: "resource") { resource in + resource["meta"] = ["profile": [provenanceProfiles["health-connect"] ?? ""]] + guard let agents else { + return + } + let assembler = try #require((resource["agent"] as? [[String: Any]])?.first?["who"] as? [String: Any]) + let converter = try #require(assembler["reference"] as? String) + try edit(&resource, member: "entity", index: 0) { $0["agent"] = agents(converter) } + } + } + } + /// heart-rate-minimal with its Provenance claiming `adapter`'s conversion profile instead of HealthKit's. private static func governing(_ adapter: String, expected: (code: String, location: String)) -> Vector { Vector("HealthKit outputs under the \(adapter) Provenance", golden: "heart-rate-minimal", expected: expected) { bundle in From 3ca2a3d21bed67aa8c50abc90f6b12c7e749f2c7 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 15:06:39 +0200 Subject: [PATCH 030/220] Refuse Graph Bytes Carrying Members the FHIR Model Does Not Keep Fix-round step G3, audit ledger section 2 confirmed finding 8: ExchangeGraph(validating:kind:) accepted and kept members the FHIR model never sees, although `json` is documented as the bytes to upload (the audit injected members into all 252 golden inputs; every one was accepted and kept). Every rule decides over the decoded model, so such a member would travel unchecked. - After the model checks, decodeValidated compares the given bytes with the decoded Bundle's own encoding by shape (LosslessJSONValue.shape: every scalar blanked, members and elements kept) and refuses a difference with .invalidEntries("Serialized event carries members the model does not keep") (mobile-exchange.unclassified). Values may differ in lexeme only, because the model rewrites decimals such as 72.0; that is why the bytes are kept at all. A JSON null member, which the model drops, is refused the same way. - The init(validating:kind:) doc states the refusal and why. No production caller re-validates (audit), and no shared corpus vector carries such a member: the gated corpus suite, the questionnaire and SensorKit suites pass unchanged. Test (ExchangeGraphBytesTests.revalidationRefusesMembersTheModelDrops): a Bundle-level "note" member and an "unmodeled" member inside the first resource are refused; the same graph with its decimal 72 rewritten as 72.0 is accepted and keeps its bytes. Mutation proof (full GroveHealthKitFHIRTests on macOS, then reverted; unmutated: 288 total, 286 passed, 2 skipped): without the validateKeptMembers call the new test fails ("an error was expected but none was thrown"). Output diff: none (producers build graphs from models; goldens unchanged). Gates: GroveHealthKitFHIR macOS 288 total, 286 passed, 2 skipped; GroveSensorKitFHIR 83/83; GroveQuestionnaire 260/260; GroveFHIR 103/103; GROVE_LOWERED_DEPLOYMENT_TARGETS=1 xcrun swift build --target GroveFHIRContract: Build complete; swiftlint --strict: no findings; reuse lint: compliant. Co-Authored-By: Claude Opus 5.5 --- .../ExchangeGraph+Equality.swift | 9 ++++++ Sources/GroveFHIRContract/ExchangeGraph.swift | 17 +++++++++-- .../ExchangeGraphBytesTests.swift | 28 +++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/Sources/GroveFHIRContract/ExchangeGraph+Equality.swift b/Sources/GroveFHIRContract/ExchangeGraph+Equality.swift index 5a7be6b1c..4e95edafa 100644 --- a/Sources/GroveFHIRContract/ExchangeGraph+Equality.swift +++ b/Sources/GroveFHIRContract/ExchangeGraph+Equality.swift @@ -271,6 +271,15 @@ indirect enum LosslessJSONValue: Equatable { extension LosslessJSONValue { + /// The value with every scalar blanked: which members and elements exist, not what they hold. + var shape: LosslessJSONValue { + switch self { + case .object(let members): .object(members.mapValues(\.shape)) + case .array(let elements): .array(elements.map(\.shape)) + case .string, .number, .boolean, .null: .null + } + } + /// Token equality, with strings, lexemes and member names compared scalar by scalar. static func == (lhs: LosslessJSONValue, rhs: LosslessJSONValue) -> Bool { switch (lhs, rhs) { diff --git a/Sources/GroveFHIRContract/ExchangeGraph.swift b/Sources/GroveFHIRContract/ExchangeGraph.swift index 606bb1b77..b59d3a555 100644 --- a/Sources/GroveFHIRContract/ExchangeGraph.swift +++ b/Sources/GroveFHIRContract/ExchangeGraph.swift @@ -88,6 +88,8 @@ public struct ExchangeGraph: Sendable { /// /// It applies every structural rule a built graph passes, including that each adapter output has exactly one conversion /// Provenance of its adapter; StructureDefinition and terminology conformance is the conformance lane's to prove. + /// Bytes carrying a member the FHIR model does not keep are refused: the rules decide over what the model holds, and + /// ``json`` is what travels, so such a member would travel unchecked. /// /// Serialized checks run first, because Foundation keeps only one of duplicate members and /// decoding through `Foundation.URL` could normalize an identity system or collapse a @@ -144,17 +146,28 @@ public struct ExchangeGraph: Sendable { } catch { throw .ruleViolation(.mobileExchangeEventIdentity) } - // The model checks read the decoded model's own encoding, not the stored bytes: those may still - // carry members the model does not keep, and the checks decide over what the graph will hold. + // The model checks read the decoded model's own encoding, not the stored bytes, and decide over what the + // graph will hold; the bytes then must carry nothing more. try Self.validate( kind: kind, eventIdentifier: eventIdentifier, bundle: decodedBundle, document: ValidationDocument(bundle: decodedBundle, jsonData: nil) ) + try Self.validateKeptMembers(of: jsonData, decoded: decodedBundle) return (eventIdentifier, decodedBundle) } + /// Whether the bytes name exactly the members and elements the decoded model encodes; values may differ in + /// lexeme only, as the model rewrites a decimal such as `72.0`. + private static func validateKeptMembers(of jsonData: Data, decoded bundle: ModelsR4.Bundle) throws(ExchangeGraphError) { + guard let given = try? LosslessJSONValue(parsing: jsonData), + let kept = try? LosslessJSONValue(parsing: wireEncoder.encode(bundle)), + given.shape == kept.shape else { + throw .invalidEntries("Serialized event carries members the model does not keep") + } + } + /// Runs `body` in its own autorelease pool where there is one, so the Foundation temporaries of /// encoding, parsing and validating one graph are released with that graph rather than with the /// caller's pool, which a batch conversion may not drain until thousands of graphs later. diff --git a/Tests/GroveHealthKitFHIRTests/ExchangeGraphBytesTests.swift b/Tests/GroveHealthKitFHIRTests/ExchangeGraphBytesTests.swift index c4d017a38..1ede03eee 100644 --- a/Tests/GroveHealthKitFHIRTests/ExchangeGraphBytesTests.swift +++ b/Tests/GroveHealthKitFHIRTests/ExchangeGraphBytesTests.swift @@ -68,6 +68,34 @@ struct ExchangeGraphBytesTests { #expect(restored.isSemanticallyEqual(to: graph)) } + /// The bytes are what travels, while the rules decide over the model, so a member the model drops is refused, at + /// the Bundle and inside a resource alike; a decimal lexeme the model rewrites is not a dropped member. + @Test("Re-validation refuses members the FHIR model does not keep") + func revalidationRefusesMembersTheModelDrops() throws { + let graph = try #require(GoldenCase.all.first).output().graph + func edited(_ change: (inout [String: Any]) throws -> Void) throws -> Data { + var bundle = try #require(try JSONSerialization.jsonObject(with: graph.json) as? [String: Any]) + try change(&bundle) + return try JSONSerialization.data(withJSONObject: bundle, options: [.sortedKeys, .withoutEscapingSlashes]) + } + let refusal = ExchangeGraphError.invalidEntries("Serialized event carries members the model does not keep") + #expect(throws: refusal) { + try ExchangeGraph(validating: try edited { $0["note"] = "not a Bundle element" }, kind: graph.kind) + } + #expect(throws: refusal) { + try ExchangeGraph(validating: try edited { bundle in + var entries = try #require(bundle["entry"] as? [[String: Any]]) + var resource = try #require(entries[0]["resource"] as? [String: Any]) + resource["unmodeled"] = ["value": 1] + entries[0]["resource"] = resource + bundle["entry"] = entries + }, kind: graph.kind) + } + let rewritten = Data(String(decoding: graph.json, as: UTF8.self).replacingOccurrences(of: #""value":72}"#, with: #""value":72.0}"#).utf8) + #expect(rewritten != graph.json) + #expect(try ExchangeGraph(validating: rewritten, kind: graph.kind).json == rewritten) + } + @Test("The earlier spelling forwards to the validating initializer") func earlierSpellingForwards() throws { let graph = try #require(GoldenCase.all.first).output().graph From bc3e1598b21fdefcca9d13783a2d4ebcca6c7aad Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 15:14:36 +0200 Subject: [PATCH 031/220] Pin the Refusal Order and Sync-Pair Refusals Through the Converter Itself Fix-round step G3, audit ledger section 4 confirmed findings 3 (documents with a malformed sync pair are refused, untested and recorded as kept behaviour), 4 (the refusal-check order changed: content before envelope) and the first part of 6 (the sync-identity tests ran against a test seam that copied the assembler's writer-record decoration). Finding 4, decided: keep content before origin, document it, pin it. The old pipeline's order (envelope, then content, then the sync pair) was incidental: its content builders took the envelope's graph context, and it validated the sync pair, an origin fact, after the content anyway, so it followed no envelope-first rule. The guide prescribes no precedence among producer refusals and both orders are deterministic. Content first keeps a record's refusal independent of the deployment's writer policy: under one classification an invalid source bundle identifier refuses the record, under another it is never read. HealthKitConversionError now documents the order: source type, content (values, units, effective times), then origin (recording device, writer, sync identifier and version). Finding 3: the refusal is the IG-compliant behaviour (ig-pin healthkit/input/pagecontent/mapping.md:45 requires rejecting a half pair, a blank or non-String identifier or a version that is not an integral non-negative number, for every HealthKit source record), an agreed fix kept by owner decision. The WriterPolicy doc now says a malformed pair refuses the record, recording documents included, which carry no writer-record identity. Finding 6 (sync seam): HealthKitConverter.applySyncIdentity, a test-only copy of the assembler's decoration, is deleted. Its two tests now convert a stored body mass attributed to a connected scale's application: syncIdentityIsCarried compares the writer-record identifier with the one the identity scope mints for that writer and sync identifier, and the UInt64.max version with "18446744073709551615"; syncIdentityRejectsMalformedPairs converts each malformed pair (half pairs; true, -1, 1.5, "1", NaN versions; "" and 1 identifiers) and expects the converter's own refusal. The metadata is written by the new StoredSampleFixtures.withMetadata past HealthKit's initializer, which raises an Objective-C exception for most of these. Tests: - HealthKitFHIRExporterTests.refusalOrderIsContentWriterSyncPair: under a writer policy classifying every source, a heart rate with an unsupported motion context, an invalid writer bundle identifier and a half sync pair is refused for its motion context; the same without the content fault for its writer. - ExchangeEnvelopeFixTests.documentsRefuseAMalformedSyncPair (F10 spec, :154): a heartbeat series with a half pair, and one with sync version 1.5, are refused with invalidValue(.heartbeatSeries, .invalidMetadataValue(.syncVersion)). Mutation proof (each applied alone, full GroveHealthKitFHIRTests on macOS, then reverted; unmutated: 290 total, 288 passed, 2 skipped): - SourceFacts resolved before the content: fails refusalOrderIsContentWriterSyncPair. - the sync pair validated before the writer: fails it too. - a heartbeat series skips its sync pair: fails documentsRefuseAMalformedSyncPair. - fractional sync versions accepted: fails documentsRefuseAMalformedSyncPair and syncIdentityRejectsMalformedPairs. - the writer record scoped to another application: fails syncIdentityIsCarried (and writerRecordTravelsUnderEveryWriterPolicy and the writer-blank-name-with-sync-identity golden). Output diff: none (goldens byte-identical; source changes are doc comments). Gates: GroveHealthKitFHIR macOS 290 total, 288 passed, 2 skipped; swiftlint --strict: no findings; reuse lint: compliant. Co-Authored-By: Claude Opus 5.5 --- .../HealthKitConversionError.swift | 4 + .../HealthKitFHIRExporter+Options.swift | 5 +- .../ExchangeEnvelopeFixTests.swift | 20 ++++ .../HealthKitConverter+TestSeams.swift | 24 ----- .../HealthKitConverterTests.swift | 97 ++++++------------- .../HealthKitFHIRExporterTests.swift | 23 +++++ .../StoredSampleFixtures.swift | 10 ++ 7 files changed, 92 insertions(+), 91 deletions(-) diff --git a/Sources/GroveHealthKitFHIR/HealthKitConversionError.swift b/Sources/GroveHealthKitFHIR/HealthKitConversionError.swift index 2e5240211..351f6d62b 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConversionError.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConversionError.swift @@ -126,6 +126,10 @@ public struct HealthKitDependencyFailure: Error, Equatable, Sendable { /// A fail-closed refusal from the HealthKit conversion facade; every case reports one registry code. +/// +/// A record with several faults is refused for the first in this order, whatever the options: its source type, then +/// its content (values, units, effective times), then what it states about its origin (its recording device, its +/// writer, its sync identifier and version). A content fault thus reads the same under every writer policy. public enum HealthKitConversionError: Error, Equatable, Sendable { /// The identifier is not in the adapter inventory at all. case unregisteredSourceType(String) diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift index 8b7df70e3..aa2f17830 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift @@ -54,7 +54,10 @@ extension HealthKitFHIRExporter { /// a source nobody classified states no writer. Only the caller's explicit classification states one. The /// physical unit a sample was measured on is the recording Device, which ``RecordingDevicePolicy`` /// resolves from `HKDevice` whatever this policy says. A sample's sync identifier and version likewise - /// travel as its writer-record identity, scoped to the source's bundle identifier, under every policy. + /// travel as its writer-record identity, scoped to the source's bundle identifier, under every policy; a + /// malformed pair (a half pair, a blank or non-text identifier, a version that is not a non-negative integral + /// number) refuses the record, a recording document too, although a document carries no writer-record identity + /// (HealthKit guide `mapping.md`, logical identity and revisions). public enum WriterPolicy: Sendable { /// No writer is stated, and the Provenance names no author. The default. case omit diff --git a/Tests/GroveHealthKitFHIRTests/ExchangeEnvelopeFixTests.swift b/Tests/GroveHealthKitFHIRTests/ExchangeEnvelopeFixTests.swift index 02301ccec..6002c0b60 100644 --- a/Tests/GroveHealthKitFHIRTests/ExchangeEnvelopeFixTests.swift +++ b/Tests/GroveHealthKitFHIRTests/ExchangeEnvelopeFixTests.swift @@ -100,6 +100,26 @@ struct ExchangeEnvelopeFixTests { } #endif + /// The guide requires the pair be rejected on every HealthKit source record (mapping.md, logical identity and + /// revisions), so a document refuses a malformed pair although it would not state the identity. + @Test("A document refuses a malformed sync pair, as every HealthKit source record does") + @available(*, deprecated, message: "Exercises the deprecated converter's document path") + func documentsRefuseAMalformedSyncPair() throws { + let malformed: [[String: any Sendable]] = [ + [HKMetadataKeyTimeZone: GoldenFixtures.timeZone, HKMetadataKeySyncIdentifier: "series-1"], + [HKMetadataKeyTimeZone: GoldenFixtures.timeZone, HKMetadataKeySyncIdentifier: "series-1", HKMetadataKeySyncVersion: 1.5] + ] + for metadata in malformed { + var shape = GoldenCase.seriesShape(uuid: 89, duration: 2) + shape.metadata = metadata + let series = try StoredSampleFixtures.seriesSample(HKHeartbeatSeriesSample.self, sampleType: HKSeriesType.heartbeat(), shape: shape) + let record = HealthKitHeartbeatSeriesRecord(series: series, heartbeats: [HealthKitHeartbeat(timeSinceSeriesStart: 0, precededByGap: false)]) + #expect(throws: HealthKitConversionError.invalidValue(.heartbeatSeries, .invalidMetadataValue(.syncVersion))) { + try HealthKitConverter().convert(record, context: HealthKitConversionContext()) + } + } + } + @Test("Event instants are written in UTC at millisecond precision, without binary noise") @available(*, deprecated, message: "Exercises the deprecated converter, which takes any instant") func eventInstantsAreMilliseconds() throws { diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitConverter+TestSeams.swift b/Tests/GroveHealthKitFHIRTests/HealthKitConverter+TestSeams.swift index ad851400c..a278f6787 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitConverter+TestSeams.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitConverter+TestSeams.swift @@ -79,30 +79,6 @@ extension HealthKitConverter { } return try locationTrackPayload(locations) } - - // HealthKit itself models the metadata dictionary as absent when an object has no metadata. - /// Applies Apple's paired sync metadata exactly as the assembler decorates an output with it. - static func applySyncIdentity( - metadata: [String: Any]?, // swiftlint:disable:this discouraged_optional_collection - writerApplication: String, - to observation: inout Observation, - context: HealthKitConversionContext - ) throws { - guard let record = try HealthKitAssembly.SourceFacts.writerRecord(metadata: metadata, writerApplication: writerApplication) else { - return - } - let identity = try context.identityScope.writerRecord( - writerApplication: BusinessIdentifier( - system: IdentifierSystem(Canonicals.appleBundleIdentifierSystem), - value: record.writerApplication - ), - writerRecordID: record.syncIdentifier - ) - observation.identifier = (observation.identifier ?? []) + [identity.fhirIdentifier] - observation.extension = (observation.extension ?? []) + [ - Extension(url: Canonicals.writerRecordVersion, value: .string(record.version.asFHIRStringPrimitive())) - ] - } } #endif diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitConverterTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitConverterTests.swift index 744c2bf40..87a29160c 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitConverterTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitConverterTests.swift @@ -255,85 +255,50 @@ struct HealthKitFHIRConverterTests { // The object identifiers differ, which is exactly why the sync identity is needed. #expect(first.observation.identifier?.first != revision.observation.identifier?.first) - // Exercise the production mapper through its source-attribution seam. HealthKit's public - // sample factory does not let a unit test construct the HKSourceRevision that owns it. - var attributable = plain.observation - try HealthKitConverter.applySyncIdentity( - metadata: [ - HKMetadataKeySyncIdentifier: "scale-2026-08-19", - HKMetadataKeySyncVersion: NSNumber(value: UInt64.max) - ], - writerApplication: "org.example.connected-scale", - to: &attributable, + // A stored sample names the writing application, so the pair is scoped to it: the identity is the one the + // identity scope mints for that writer and record, and a UInt64 version survives as canonical decimal text. + let attributable = try converter.convert( + attributedBodyMass([HKMetadataKeySyncIdentifier: "scale-2026-08-19", HKMetadataKeySyncVersion: NSNumber(value: UInt64.max)]), context: context ) - #expect(attributable.identifier?.contains { (try? RoledIdentifier($0).role) == .writerRecord } == true) - guard case .string(let version)? = attributable.extension? - .first(where: { $0.url == Canonicals.writerRecordVersion })?.value else { - Issue.record("The attributable writer carries its record version") - return - } - #expect(version.value?.string == "18446744073709551615") + let expected = try context.identityScope.writerRecord( + writerApplication: BusinessIdentifier(system: IdentifierSystem(Canonicals.appleBundleIdentifierSystem), value: "org.example.connected-scale"), + writerRecordID: "scale-2026-08-19" + ) + #expect(syncIdentifier(attributable) == expected.identifier.value) + #expect(syncVersion(attributable) == "18446744073709551615") } @Test("HealthKit sync identifier and version are a strict nonnegative-integral pair") func syncIdentityRejectsMalformedPairs() throws { - let plain = try converter.convert( - quantitySample(.bodyMass, unit: .gramUnit(with: .kilo), value: 68.4), - context: context - ) - let invalidIdentifier = HealthKitValueFailure.invalidMetadataValue(.syncIdentifier) - let invalidVersion = HealthKitValueFailure.invalidMetadataValue(.syncVersion) - - #expect(throws: invalidVersion) { - var observation = plain.observation - try HealthKitConverter.applySyncIdentity( - metadata: [HKMetadataKeySyncIdentifier: "logical-record"], - writerApplication: "org.example.writer", - to: &observation, - context: context - ) - } - #expect(throws: invalidIdentifier) { - var observation = plain.observation - try HealthKitConverter.applySyncIdentity( - metadata: [HKMetadataKeySyncVersion: 1], - writerApplication: "org.example.writer", - to: &observation, - context: context - ) - } - + let invalidIdentifier = HealthKitConversionError.invalidValue(.bodyMass, .invalidMetadataValue(.syncIdentifier)) + let invalidVersion = HealthKitConversionError.invalidValue(.bodyMass, .invalidMetadataValue(.syncVersion)) + var malformed: [([String: Any], HealthKitConversionError)] = [ + ([HKMetadataKeySyncIdentifier: "logical-record"], invalidVersion), + ([HKMetadataKeySyncVersion: 1], invalidIdentifier) + ] for invalid in [true, -1, 1.5, "1", NSNumber(value: Double.nan)] as [Any] { - #expect(throws: invalidVersion) { - var observation = plain.observation - try HealthKitConverter.applySyncIdentity( - metadata: [ - HKMetadataKeySyncIdentifier: "logical-record", - HKMetadataKeySyncVersion: invalid - ], - writerApplication: "org.example.writer", - to: &observation, - context: context - ) - } + malformed.append(([HKMetadataKeySyncIdentifier: "logical-record", HKMetadataKeySyncVersion: invalid], invalidVersion)) } for invalid in ["", 1] as [Any] { - #expect(throws: invalidIdentifier) { - var observation = plain.observation - try HealthKitConverter.applySyncIdentity( - metadata: [ - HKMetadataKeySyncIdentifier: invalid, - HKMetadataKeySyncVersion: 1 - ], - writerApplication: "org.example.writer", - to: &observation, - context: context - ) + malformed.append(([HKMetadataKeySyncIdentifier: invalid, HKMetadataKeySyncVersion: 1], invalidIdentifier)) + } + for (metadata, refusal) in malformed { + let sample = try attributedBodyMass(metadata) + #expect(throws: refusal, "\(metadata)") { + try converter.convert(sample, context: context) } } } + /// A stored body mass written by a connected scale's application, carrying exactly `metadata`, written past + /// HealthKit's initializer, which raises for most malformed sync pairs and for a version above Int64. + private func attributedBodyMass(_ metadata: [String: Any]) throws -> HKQuantitySample { + let writer = StoredSampleFixtures.Writer(name: "Connected Scale", bundleIdentifier: "org.example.connected-scale", version: "7", productType: "iPhone17,1") + let sample = quantitySample(.bodyMass, unit: .gramUnit(with: .kilo), value: 68.4) + return try StoredSampleFixtures.withMetadata(StoredSampleFixtures.stored(sample, uuid: GoldenFixtures.uuid(0xD0), writer: writer), metadata) + } + private func quantitySample( _ type: HKQuantityTypeIdentifier, diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift index 658a9d05f..00bf3db46 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift @@ -270,6 +270,29 @@ struct HealthKitFHIRExporterTests { #expect(provenance.target.compactMap { $0.identifier?.value?.value?.string } == [session]) } + /// One refusal per record, chosen in a fixed order whatever the options: content, then writer, then sync pair. + @Test("A record with several faults reports its content first, then its writer, then its sync pair") + func refusalOrderIsContentWriterSyncPair() throws { + let exporter = try Self.exporter { $0.writer = .classify { _ in .application } } + var writer = GoldenFixtures.foreignWriter + writer.bundleIdentifier = "not a bundle id" + func heartRate(_ ordinal: UInt8, _ metadata: [String: Any]) throws -> HKQuantitySample { + try StoredSampleFixtures.withMetadata(GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(ordinal), writer: writer), metadata) + } + let samples = [ + try heartRate(0xD1, [HKMetadataKeyHeartRateMotionContext: 99, HKMetadataKeySyncIdentifier: "half"]), + try heartRate(0xD2, [HKMetadataKeySyncIdentifier: "half"]) + ] + let (exports, _) = try Self.collect(exporter, samples) + let reasons = exports.map { export -> HealthKitConversionError? in + guard case .refused(let reason) = export.outcome else { + return nil + } + return reason + } + #expect(reasons == [.invalidValue(.heartRate, .unsupportedMetadataValue(.heartRateMotionContext)), .sourceApplicationInvalid]) + } + @Test("An export shares one receipt; an error in the receiver ends the call with the reservations kept") func receiverErrorsPropagate() throws { struct Stop: Error {} diff --git a/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift b/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift index 2de7317bd..7549a5772 100644 --- a/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift +++ b/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift @@ -110,6 +110,16 @@ enum StoredSampleFixtures { return sample } + /// `sample` carrying exactly `metadata`, written past HealthKit's initializer, which raises an Objective-C exception + /// for a value it refuses (a half sync pair, a negative or textual sync version) instead of returning one. + static func withMetadata(_ sample: Sample, _ metadata: [String: Any]) throws -> Sample { + try write(metadata as NSDictionary, to: "metadata", of: sample) + guard (sample.metadata ?? [:]).keys.sorted() == metadata.keys.sorted() else { + throw FixtureError.keyNotHonored(key: "metadata", class: String(describing: type(of: sample))) + } + return sample + } + /// A bare instance of a sample class without a public initializer, carrying exactly `shape`. static func seriesSample(_ type: Sample.Type, sampleType: HKSampleType, shape: SeriesShape) throws -> Sample { let object = try allocate(type) From 514b6254c25b7cafd2ac5b9dc47b2f4794b6b2db Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 15:17:03 +0200 Subject: [PATCH 032/220] Remove Dead Assembly Code and Refuse an Empty Output List Before Indexing It Fix-round step G3, audit ledger section 4 confirmed finding 7 (dead or latent code): - ExchangeAssemblyError.writerInvalid was never thrown (the writer's validity is SourceFacts' to refuse, as sourceApplicationInvalid) but was mapped in HealthKitConversionError(conversionFailure:); the case and its mapping are deleted (package API). - HealthKitConverter.applyManualRecordingMethod had no caller and restated the assembler's manual-entry extension; deleted. - The adapter ID was two literals (HealthKitAssembly.adapter and HealthKitConverter.adapterID); the assembly's contract now reads HealthKitConverter.adapterID, so they cannot split. - HealthKitAssembly.graph indexed outputs[0] before the assembler's empty-outputs guard, which would trap; it now refuses an empty list with the assembler's own ExchangeAssemblyError.noOutputs first. Unreachable today (every caller passes at least the primary), so no test pins it. Output diff: none (goldens byte-identical; the GroveHealthKitFHIR suite, which includes every golden and the G17 table, passes unchanged). Gates: GroveHealthKitFHIR macOS 290 total, 288 passed, 2 skipped; GroveSensorKitFHIR 83/83; GroveQuestionnaire 260/260; GROVE_LOWERED_DEPLOYMENT_TARGETS=1 xcrun swift build --target GroveFHIRContract: Build complete; swiftlint --strict: no findings; reuse lint: compliant. Co-Authored-By: Claude Opus 5.5 --- Sources/GroveFHIRContract/ExchangeGraphDraft.swift | 2 -- Sources/GroveHealthKitFHIR/HealthKitAssembly.swift | 5 ++++- .../HealthKitConversionError.swift | 2 -- .../HealthKitConverter+Observation.swift | 14 -------------- 4 files changed, 4 insertions(+), 19 deletions(-) diff --git a/Sources/GroveFHIRContract/ExchangeGraphDraft.swift b/Sources/GroveFHIRContract/ExchangeGraphDraft.swift index 66b891bd5..67fde0366 100644 --- a/Sources/GroveFHIRContract/ExchangeGraphDraft.swift +++ b/Sources/GroveFHIRContract/ExchangeGraphDraft.swift @@ -198,8 +198,6 @@ package enum ExchangeAssemblyError: Error, Equatable, Sendable { case repositoryIDWithoutNode(ExchangeGraphNode) /// The draft states no output. case noOutputs - /// The source's application or host facts do not form a valid Device. - case writerInvalid } diff --git a/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift b/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift index 5ee091401..75905b33f 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift @@ -65,7 +65,7 @@ struct HealthKitAssembly: Sendable { static let outputRevision: UInt = 2 static let adapter = ExchangeAdapterContract( - adapterID: "healthkit", + adapterID: HealthKitConverter.adapterID, provenanceProfile: HealthKitContract.conversionProvenanceProfile, applicationDeviceProfile: HealthKitContract.applicationDeviceProfile ) { application in @@ -133,6 +133,9 @@ struct HealthKitAssembly: Sendable { outputs: [ExchangeOutputDraft], request: Request ) throws -> HealthKitConversion { + guard !outputs.isEmpty else { + throw ExchangeAssemblyError.noOutputs + } let source = HealthKitSourceRecord(uuid: sample.uuid, type: type) let facts = try SourceFacts(sample, options: request.options) var outputs = outputs diff --git a/Sources/GroveHealthKitFHIR/HealthKitConversionError.swift b/Sources/GroveHealthKitFHIR/HealthKitConversionError.swift index 351f6d62b..4b1c477ac 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConversionError.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConversionError.swift @@ -256,8 +256,6 @@ extension HealthKitConversionError { self = .exchangeGraph(error) case .repositoryIDWithoutNode(let node) as ExchangeAssemblyError: self = .repositoryIDWithoutNode(node) - case ExchangeAssemblyError.writerInvalid: - self = .sourceApplicationInvalid default: self = .dependency(HealthKitDependencyFailure(underlying: error)) } diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+Observation.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+Observation.swift index b5efd5232..c05d04e01 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+Observation.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter+Observation.swift @@ -345,20 +345,6 @@ extension HealthKitConverter { ])) ) } - - static func applyManualRecordingMethod(to observation: inout Observation) { - observation.append( - extension: Extension( - url: Canonicals.recordingMethod, - value: .coding(Coding( - code: "manual-entry", - display: "Manual entry", - system: Canonicals.recordingMethodCodeSystem - )) - ), - behaviour: .replace - ) - } } #endif From d310a32558efe770311c63e98058d6e2070905ac Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 15:20:05 +0200 Subject: [PATCH 033/220] Carry a Gateway Application Only Beside an Observation in the Sensor Adapters Fix-round step G3, audit ledger section 5 confirmed finding 2: spec F2 (no gateway Device on graphs no Observation of which names it) was applied to the shared assembler only. The generic Sensor and the SensorKit converters still minted the .gatewayApplication snapshot for every record, so a Sensor recording document and a raw-only SensorKit record under a gateway application were refused with mobile-support.connected (the snapshot connects to nothing: the guide defines observation-gatewayDevice for Observations only). Spec F2 step 6 names both one-line changes. - SensorConverter: the gateway snapshot is minted after the primary resource, and only when it is an Observation. - SensorKitConverter: the gateway snapshot is minted after the Observations, and only when there is one (buildObservations returns none without a structured node, matching the entry guard). - The gatewayApplication docs say when the second snapshot travels. F2 step 7 (a gateway equal to the converter becomes the converter's entry) stays unimplemented in all three adapters, as in 2569b5c4: it is not part of D2 and not on the agreed-fix list. Output: those records, refused before, now convert and carry no gateway Device and no gateway extension; every graph that converted before is byte-identical (GroveSensorKitFHIR suite and its fixtures unchanged, the sensor guide conformance fixtures use .gateway). Tests (GroveSensorKitFHIRTests): - SensorFHIRConverterTests.gatewayApplicationTravelsOnlyWithAnObservation: under .gatewayApplication a recording document has no gateway snapshot entry; a sampled-data Observation has it. - GroveSensorKitFHIRConverterTests.gatewayApplicationTravelsOnlyWithAnObservation: the same for a raw-only heart-rate record and a hybrid ECG record. - ExchangeEventContext.with(converterRole:) in the test support re-roles a test event. Mutation proof (each applied alone, full GroveSensorKitFHIR suite on macOS, then reverted; unmutated: 85/85): minting the gateway unconditionally again in SensorConverter, or in SensorKitConverter, fails that adapter's new test with mobile-support.connected. Gates: GroveSensorKitFHIR macOS 85/85; swiftlint --strict on Sources/GroveSensorKitFHIR and Tests/GroveSensorKitFHIRTests: no findings; reuse lint: compliant. GroveFHIRContract and GroveHealthKitFHIR unchanged. Co-Authored-By: Claude Opus 5.5 --- .../GroveSensorKitFHIR/SensorConverter.swift | 8 +++-- .../SensorKitConverter.swift | 5 +-- .../SensorConverterTests.swift | 18 ++++++++++ .../SensorFHIRIdentityTestSupport.swift | 19 ++++++++++ .../SensorKitConverterTests.swift | 35 +++++++++++++++++++ 5 files changed, 80 insertions(+), 5 deletions(-) diff --git a/Sources/GroveSensorKitFHIR/SensorConverter.swift b/Sources/GroveSensorKitFHIR/SensorConverter.swift index 10a8c21cf..76654a8e5 100644 --- a/Sources/GroveSensorKitFHIR/SensorConverter.swift +++ b/Sources/GroveSensorKitFHIR/SensorConverter.swift @@ -220,7 +220,6 @@ extension SensorConverter { let converterHostURL = try converterHostIdentity.fullURLString let recordingDeviceURL = try recordingDeviceSnapshot.map { try $0.fullURLString } let studyContext = try context.event.studyContext() - let gateway = try gatewayApplication(context: context) var converterApplication = applicationDevice(context.event.application) converterApplication.id = context.repositoryID(.applicationDevice)?.primitive @@ -246,6 +245,9 @@ extension SensorConverter { recordingDeviceURL: recordingDeviceURL, converterURL: converterURL ) + // The guide defines observation-gatewayDevice for Observations only; a recording document names no gateway, so + // a gateway snapshot beside one would connect to nothing (mobile-support.connected). + let gateway: IdentifiedDevice? = if case .observation = primaryResource { try gatewayApplication(context: context) } else { nil } // The repository id is applied once; the proxy and the retained value are the same resource. let retainedPrimary: SensorPrimaryResource let primaryProxy: ResourceProxy @@ -343,8 +345,8 @@ extension SensorConverter { return ["Observation.effectivePeriod.start", "Observation.effectivePeriod.end"].map { .sourceOffsetUnavailable(field: $0) } } - /// A distinct gateway application travels as a second application snapshot; the converter - /// itself as gateway needs no further entry. + /// A distinct gateway application travels as a second application snapshot when the primary is an Observation, + /// which names it; the converter itself as gateway needs no further entry. static func gatewayApplication(context: SensorConversionContext) throws -> IdentifiedDevice? { guard case .gatewayApplication(let application) = context.event.converterRole else { return nil diff --git a/Sources/GroveSensorKitFHIR/SensorKitConverter.swift b/Sources/GroveSensorKitFHIR/SensorKitConverter.swift index 6b0887f9b..a03f676c5 100644 --- a/Sources/GroveSensorKitFHIR/SensorKitConverter.swift +++ b/Sources/GroveSensorKitFHIR/SensorKitConverter.swift @@ -272,7 +272,6 @@ extension SensorKitConverter { let converterURL = try converterApplicationIdentity.fullURLString let converterHostURL = try converterHostIdentity.fullURLString let studyContext = try context.event.studyContext() - let gateway = try gatewayApplication(context: context) let recordingDeviceIdentity = try context.recordingDevice.map { try context.identityScope.recordingDevice( adapterID: Self.adapterID, @@ -300,6 +299,8 @@ extension SensorKitConverter { recordingDeviceURL: recordingDeviceURL, converterURL: converterURL ) + // Only an Observation names a gateway (observation-gatewayDevice): a raw-only graph carries none. + let gateway = try observations.isEmpty ? nil : gatewayApplication(context: context) var document = try buildDocument( record, sourceIdentifier: sourceRecord.identifier, @@ -499,7 +500,7 @@ extension SensorKitConverter { try validateCatalogContract(record) } - /// A distinct gateway application travels as a second application snapshot. + /// A distinct gateway application travels as a second application snapshot when the graph emits an Observation. static func gatewayApplication(context: SensorKitConversionContext) throws -> IdentifiedDevice? { guard case .gatewayApplication(let application) = context.event.converterRole else { return nil diff --git a/Tests/GroveSensorKitFHIRTests/SensorConverterTests.swift b/Tests/GroveSensorKitFHIRTests/SensorConverterTests.swift index a580f2385..a0f0468c8 100644 --- a/Tests/GroveSensorKitFHIRTests/SensorConverterTests.swift +++ b/Tests/GroveSensorKitFHIRTests/SensorConverterTests.swift @@ -129,6 +129,24 @@ struct SensorFHIRConverterTests { #expect(value.data?.value?.string == "0.1 0.2 0.3 0.4 0.5 0.6") } + /// Spec F2 in the generic sensor adapter: the guide defines observation-gatewayDevice for Observations only, so a + /// recording document under a gateway application carries no gateway Device, while an Observation names it. + @Test + func gatewayApplicationTravelsOnlyWithAnObservation() throws { + let base = try Self.context + let gateway = ApplicationDevice.test(name: "Cuff Companion", bundleIdentifier: "com.example.cuff", version: "3.1") + let context = SensorConversionContext( + event: base.event.with(converterRole: .gatewayApplication(gateway)), + adapterID: base.adapterID, + recordingDevice: base.recordingDevice + ) + let snapshot = try context.identityScope.deviceSnapshot(event: context.eventIdentifier, role: .application, sourceDeviceToken: gateway.sourceDeviceToken) + let document = try SensorConverter().convert(.recordingDocument(Self.recordingDocument()), context: context) + #expect(document.graph.entry(fullURL: try snapshot.fullURL) == nil) + let observation = try SensorConverter().convert(.sampledData(Self.sampledData()), context: context) + #expect(observation.graph.entry(fullURL: try snapshot.fullURL) != nil) + } + @Test func repositoryIDsAreAppliedOnlyWhenExplicitlyAssigned() throws { let base = try Self.context diff --git a/Tests/GroveSensorKitFHIRTests/SensorFHIRIdentityTestSupport.swift b/Tests/GroveSensorKitFHIRTests/SensorFHIRIdentityTestSupport.swift index c02478aae..46db4f48e 100644 --- a/Tests/GroveSensorKitFHIRTests/SensorFHIRIdentityTestSupport.swift +++ b/Tests/GroveSensorKitFHIRTests/SensorFHIRIdentityTestSupport.swift @@ -143,6 +143,25 @@ extension RoledIdentifier { } +extension ExchangeEventContext { + /// The same event under another converter role. + func with(converterRole: ConverterRole) -> ExchangeEventContext { + ExchangeEventContext( + subject: subject, + event: event, + identityScope: identityScope, + repositoryScope: repositoryScope, + application: application, + host: host, + conversionInstant: conversionInstant, + converterRole: converterRole, + studies: studies, + repositoryIDs: repositoryIDs + ) + } +} + + /// Keeps the fixtures concise while production callers build the shared event context themselves. extension SensorConversionContext { init( diff --git a/Tests/GroveSensorKitFHIRTests/SensorKitConverterTests.swift b/Tests/GroveSensorKitFHIRTests/SensorKitConverterTests.swift index 72222e1ff..c8df26cd6 100644 --- a/Tests/GroveSensorKitFHIRTests/SensorKitConverterTests.swift +++ b/Tests/GroveSensorKitFHIRTests/SensorKitConverterTests.swift @@ -495,6 +495,41 @@ struct GroveSensorKitFHIRConverterTests { #expect(period.start == period.end) } + /// Spec F2 in the SensorKit adapter: only an Observation names a gateway, so a raw-only graph under a gateway + /// application carries no gateway Device, while a hybrid ECG graph, whose Observation names it, does. + @Test("A gateway application travels only with an Observation that names it") + func gatewayApplicationTravelsOnlyWithAnObservation() throws { + let base = try Self.context + let gateway = ApplicationDevice.test(name: "Cuff Companion", bundleIdentifier: "com.example.cuff", version: "3.1") + let context = SensorKitConversionContext( + event: base.event.with(converterRole: .gatewayApplication(gateway)), + visitLocationIdentifierSystem: base.visitLocationIdentifierSystem, + recordingDevice: base.recordingDevice, + sourceTimeZone: base.sourceTimeZone + ) + let snapshot = try context.identityScope.deviceSnapshot(event: context.eventIdentifier, role: .application, sourceDeviceToken: gateway.sourceDeviceToken) + let raw = try SensorKitRawRecord( + sourceRecordID: try Self.sourceID, + sourceToken: "SRSensor.heartRate", + effectivePeriod: DateInterval(start: Self.start, duration: 1), + nativeRecording: try Self.native(format: .heartRateSamples) + ) + let rawOnly = try SensorKitConverter().convert(.raw(raw), context: context) + #expect(rawOnly.graph.entry(fullURL: try snapshot.fullURL) == nil) + let ecg = SensorKitECGRecord( + sourceRecordID: try Self.sourceID, + startDate: Self.start, + durationSeconds: 0.006, + frequencyHertz: 500, + lead: .leftArmMinusRightArm, + guidance: .guided, + batches: [.init(offsetSeconds: 0, millivolts: [0.011, 0.023]), .init(offsetSeconds: 0.004, millivolts: [-0.005, 0.014])], + nativeRecording: try Self.native() + ) + let hybrid = try SensorKitConverter().convert(.electrocardiogram(ecg), context: context) + #expect(hybrid.graph.entry(fullURL: try snapshot.fullURL) != nil) + } + @Test("A raw-only source discloses its governed ID on the sole DocumentReference") func governedNativeIDOnRawOnlyPrimary() throws { let record = try SensorKitRawRecord( From 2a9f5ef15544cd2662ffe3fcafe834b05c5ed9a8 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 15:29:04 +0200 Subject: [PATCH 034/220] Correct the Docs the Rework Left Stale and Pin the ECG Retraction Gap Fix-round step G3, audit ledger section 2 confirmed findings 9 (the ExchangeInstant rounding doc) and 10 (an opt-in benchmark assertion must fail), section 3 finding 8 (docs contradicting behaviour), section 5 findings 3 (route-retraction policy consequences undocumented), 4 (an ECG without an average heart rate is retracted with a never-emitted child; owner decision: keep, IG gap, document and pin) and 5 (public docs contradicting the new behaviour); G2 leftover: the unused public import of Foundation in HealthKitFHIRExporter+Options.swift. Docs: - ExchangeInstant: the millisecond is the rounded binary64 product of the seconds and 1000, not the instant's exact value (809_059_935.6065 prints .606); the code is the agreed spec F7 behaviour, so only the wording changes. - Options.nativeIdentifier and Export.Source no longer claim the native identifier is the only way the HealthKit UUID reaches the wire: legacyBundleID .healthKitUUID repeats it as Bundle.id. - Options.route: a route deletion is retracted only while routes are authorized; switching policies leaves exported routes live or retracts never-exported ones, against the guide's exact-retraction sentence (healthkit implementation.md, retracting a source record), so keep one route policy per installation's ledger. Outcome.nothingToRetract names both cases (no outputs, or a route under .omit) and that no event is reserved. - HealthKitCatalog.outputs(for:): an ECG's average-heart-rate child is listed whether or not the ECG stated an average, so the retraction of one without names a child never emitted; the pinned guide has no source-record retraction scope yet (IG gap, draft exists). - Gateway snapshots (spec F2): ConverterRole and its gatewayApplication, RolePolicy.gatewayApplication, GroveFHIRContract.md, GroveHealthKitFHIR.md and ConfiguringAConversion.md state that the second application snapshot travels only where an Observation names it, and that recording and clinical documents carry no gateway link. - Workouts (spec F1): ConfiguringAConversion.md no longer mentions workout segments; the workoutValue comment no longer names per-activity segments. It also names DocumentReference.date beside the other event instants, in UTC at millisecond precision with ASCII digits. - BulkHealthExporter.md: both recipes used the deprecated HealthKitConverter, re-encoded Bundles and keyed stored objects by the HealthKit UUID. They now export through HealthKitFHIRExporter, store each graph's json bytes under its event identifier (the second splices them into one JSON array), return the Receipt as the processor's output and release it in didPersist, after the session recorded the batch. Benchmark (opt-in, GROVE_FHIR_BENCH_RUN=1): - The assertion compared graph.json's length with a plain JSONEncoder encoding and always failed (6795 vs 7035 bytes at N=300); it now compares graph.json with the staging encoder's bytes (sorted members, unescaped slashes), which is what the graph holds. - workoutDiagnose (the segment-refusal probe) is deleted with its GROVE_FHIR_BENCH_ONLY mode and trait; the workout scenarios keep their names for comparability, and their factory comment says the session is exported alone. Test (5.4): GoldenGraphTests.ecgRetractionNamesTheAverageHeartRateChildAlways: an ECG converted without an average heart rate emits no child, and its retraction targets the ECG and the child identity the scope mints for it. GoldenCase.electrocardiogramEvidence takes the average heart rate (default 72, unchanged for every existing caller). Mutation proof (full GroveHealthKitFHIRTests on macOS, then reverted; unmutated: 290 total, 289 passed, 1 skipped): - the catalog lists no average-heart-rate child for ECGs (an exact retraction): fails ecgRetractionNamesTheAverageHeartRateChildAlways and the retraction-electrocardiogram golden. - the benchmark run with TEST_RUNNER_GROVE_FHIR_BENCH_RUN=1, N=300, one run, only heartRate-minimal: passes (290 total, 290 passed); with the old length assertion restored it fails (6795 vs 7035). Output diff: none (doc comments, DocC and tests; goldens byte-identical). Gates: GroveHealthKitFHIR macOS 290 total, 289 passed, 1 skipped (the benchmark; workoutDiagnose is gone); swiftlint --strict: no findings; reuse lint: compliant; xcodebuild docbuild for GroveHealthKitFHIR (with GroveFHIRContract) and GroveHealthKitBulkExport on macOS: succeeded, no warning in those modules. Final gate pass of step G3 at this commit: GroveHealthKitFHIR macOS 290 total, 289 passed, 1 skipped; GroveSensorKitFHIR 85/85; GroveQuestionnaire 260/260; GroveFHIR 103/103; GROVE_LOWERED_DEPLOYMENT_TARGETS=1 xcrun swift build --target GroveFHIRContract: Build complete; swiftlint --strict on the contract, HealthKit and SensorKit sources and tests: no findings; reuse lint: compliant; Scripts/validate-fhir-conformance.sh healthkit against g3-ig (an APFS clone of the G2 scratchpad copy of ig-pin with mobile, sensor and healthkit built; GROVE_FHIR_REF its commit): "Validated 42 producer resource(s) against FHIR R4", "OK - all healthkit resources conform to their declared R4 profiles". Size (A): code 11,186 (+1,481), public 1,006 (+133) (vs baseline Grove 9b086e60; vs the step's base 28f93119: code +44, public 0. Level B: code 21,248 (+1,481), public 1,909 (+133).) Co-Authored-By: Claude Opus 5.5 --- .../ExchangeEventContext.swift | 6 +- .../GroveFHIRContract/ExchangeInstant.swift | 15 ++-- .../GroveFHIRContract.md | 2 +- .../BulkHealthExporter.md | 68 +++++++++++-------- .../ConfiguringAConversion.md | 7 +- .../GroveHealthKitFHIR.md | 3 +- .../GroveHealthKitFHIR/HealthKitCatalog.swift | 7 +- .../HealthKitConverter+Workout.swift | 3 +- .../HealthKitFHIRExporter+Options.swift | 17 +++-- .../HealthKitFHIRExporter+Results.swift | 6 +- ...onversionThroughputBenchmark+Support.swift | 3 +- .../ConversionThroughputBenchmark.swift | 35 ++-------- .../GoldenGraphCases+Documents.swift | 8 ++- .../GoldenGraphTests.swift | 26 +++++++ 14 files changed, 123 insertions(+), 83 deletions(-) diff --git a/Sources/GroveFHIRContract/ExchangeEventContext.swift b/Sources/GroveFHIRContract/ExchangeEventContext.swift index 6d4bf68fe..34ce0dc5f 100644 --- a/Sources/GroveFHIRContract/ExchangeEventContext.swift +++ b/Sources/GroveFHIRContract/ExchangeEventContext.swift @@ -10,12 +10,16 @@ public import Foundation /// How the converting application relates to the measurement it converts. +/// +/// Recording and clinical documents carry no gateway link under any role: the guide defines +/// `observation-gatewayDevice` for Observations only. public enum ConverterRole: Hashable, Sendable { /// The application assembled the graph from a record it did not mediate. case assembler /// The converting application itself mediated the measurement. case gateway - /// A distinct application mediated the measurement; it travels as a second application snapshot. + /// A distinct application mediated the measurement; graphs whose Observation outputs name it through + /// `observation-gatewayDevice` carry it as a second application snapshot, and document-only graphs carry none. case gatewayApplication(ApplicationDevice) } diff --git a/Sources/GroveFHIRContract/ExchangeInstant.swift b/Sources/GroveFHIRContract/ExchangeInstant.swift index 6439c2b08..74a55c2b6 100644 --- a/Sources/GroveFHIRContract/ExchangeInstant.swift +++ b/Sources/GroveFHIRContract/ExchangeInstant.swift @@ -12,11 +12,13 @@ package import ModelsR4 /// Converter clock instants as the wire states them: UTC, millisecond precision, ASCII. /// -/// The lexeme is computed from the instant's own binary64 value with integer arithmetic over the -/// proleptic Gregorian calendar, never through a `Formatter`, `Calendar` or `Locale`, so the same -/// instant yields the same bytes in every process, on every platform, under every locale. -/// Milliseconds are rounded half to even, trailing fraction zeros are dropped, and a whole second -/// carries no fraction: `2026-10-03T10:30:00Z`, `…:00.5Z`, `…:00.251Z`. +/// The lexeme is computed with integer arithmetic over the proleptic Gregorian calendar, never through a +/// `Formatter`, `Calendar` or `Locale`, so the same instant yields the same bytes in every process, on every +/// platform, under every locale. The millisecond is the binary64 product of the instant's seconds and 1000, +/// rounded half to even; that product is itself rounded, so an instant within half a binary64 step of a +/// millisecond tie can land on the neighbouring millisecond (`809_059_935.6065` prints `.606`). Trailing +/// fraction zeros are dropped, and a whole second carries no fraction: `2026-10-03T10:30:00Z`, `…:00.5Z`, +/// `…:00.251Z`. package enum ExchangeInstant { private struct CivilDate { let year: Int64 @@ -68,7 +70,8 @@ package enum ExchangeInstant { try DateTime(utcLexeme(date)) } - /// Milliseconds since 1970-01-01T00:00:00Z, rounded half to even from the instant's own binary64 value. + /// Milliseconds since 1970-01-01T00:00:00Z: the binary64 product of the seconds since 2001 and 1000, rounded half + /// to even, then shifted to 1970 in integers. /// /// A non-finite or out-of-range instant saturates; its lexeme then names no FHIR-representable year. package static func millisecondsSinceEpoch(_ date: Date) -> Int64 { diff --git a/Sources/GroveFHIRContract/GroveFHIRContract.docc/GroveFHIRContract.md b/Sources/GroveFHIRContract/GroveFHIRContract.docc/GroveFHIRContract.md index 9a3dd9f29..625796041 100644 --- a/Sources/GroveFHIRContract/GroveFHIRContract.docc/GroveFHIRContract.md +++ b/Sources/GroveFHIRContract/GroveFHIRContract.docc/GroveFHIRContract.md @@ -129,7 +129,7 @@ Every disclosure policy defaults to omission. A ``RepositoryID`` per ``ExchangeGraphNode`` gives a graph node the logical id your repository assigned, and nothing else in the graph changes. -``ConverterRole/gatewayApplication(_:)`` names a distinct application that mediated the measurement; it travels as a second application snapshot. +``ConverterRole/gatewayApplication(_:)`` names a distinct application that mediated the measurement; it travels as a second application snapshot when an Observation output names it through `observation-gatewayDevice`, and document-only graphs carry none. A retry is exact when ``ExchangeGraph/isSemanticallyEqual(to:)`` says so: member order, whitespace and escaping do not matter, but `72` and `72.0` are different content. diff --git a/Sources/GroveHealthKitBulkExport/GroveHealthKitBulkExport.docc/BulkHealthExporter.md b/Sources/GroveHealthKitBulkExport/GroveHealthKitBulkExport.docc/BulkHealthExporter.md index c4ac3d3e2..d6e40a4ef 100644 --- a/Sources/GroveHealthKitBulkExport/GroveHealthKitBulkExport.docc/BulkHealthExporter.md +++ b/Sources/GroveHealthKitBulkExport/GroveHealthKitBulkExport.docc/BulkHealthExporter.md @@ -40,29 +40,31 @@ See Pausing and Recovery below for checkpoint failures and restoration behavior. ### Example 1: Bulk-Upload of Historical Health Data to Firebase -This example implements a custom ``BatchProcessor``, which uploads the exported HealthKit samples received from the ``BulkHealthExporter`` into Firebase. -In this case, we implicitly define the Batch Processor's `Output` type as `Void`, since we're just interested in the uploading, and don't want to perform any additional on-device operations using the results of the individual batches. -The `conversionContext` closure both examples take mints one durable conversion context per sample; how to build it is documented in [GroveHealthKitFHIR](../../GroveHealthKitFHIR/GroveHealthKitFHIR.docc/ConfiguringAConversion.md). +This example implements a custom ``BatchProcessor``, which uploads the exported HealthKit samples received from the ``BulkHealthExporter`` into Firebase. +Both examples convert through one `HealthKitFHIRExporter`, built as [GroveHealthKitFHIR](../../GroveHealthKitFHIR/GroveHealthKitFHIR.docc/GroveHealthKitFHIR.md) describes; it mints every event through its producer's ledger. +The processor's `Output` is the exporter's `Receipt`: ``BatchProcessor/didPersist(_:)`` releases it once the session has durably recorded the batch, so a batch processed again after a crash reproduces the same events, byte for byte. +Each graph is stored as its validated `json` bytes, under its event identifier; the HealthKit UUID never names a stored object. ```swift struct FirebaseUploader: BatchProcessor { let participantID: String - /// One durable conversion context per sample: a conversion event is never shared between samples. - let contextForSample: @Sendable (HKSample) throws -> HealthKitConversionContext - let converter = HealthKitConverter() + let exporter: HealthKitFHIRExporter - func process(_ samples: consuming [Sample], of sampleType: SampleType) async throws { + func process(_ samples: consuming [Sample], of sampleType: SampleType) async throws -> HealthKitFHIRExporter.Receipt { let db = Firestore.firestore() let healthData = db.collection("participants").document(participantID).collection("healthData") let batch = db.batch() - for sample in samples { - let conversions = try converter.convert(sample, context: contextForSample(sample)) - for conversion in conversions.all { - let document = healthData.document(conversion.source.uuid.uuidString) - try batch.setData(from: conversion.bundle, for: document) + let receipt = try exporter.export(samples.map { $0 as HKSample }) { export in + if let graph = export.graph { + batch.setData(["graph": graph.json], forDocument: healthData.document(graph.event.value)) } } try await batch.commit() + return receipt + } + + func didPersist(_ receipt: HealthKitFHIRExporter.Receipt) async { + receipt.release() } } ``` @@ -78,7 +80,7 @@ let session = try await bulkExporter.session( withId: .backgroundExport, for: [SampleType.activeEnergyBurned, SampleType.heartRate, SampleType.stepCount], startDate: .oldestSample, - using: FirebaseUploader(participantID: participantID, contextForSample: conversionContext) + using: FirebaseUploader(participantID: participantID, exporter: exporter) ) // start the session @@ -87,7 +89,7 @@ try session.start() This Bulk Export Session will, in the background, go through all historical Health data for the Active Energy, Heart Rate, and Step Count quantity types, fetch the data from HealthKit, and pass it to the Batch Processor, which will then upload it to Firebase. Firebase is only the destination chosen by this example; `GroveHealthKitFHIR` neither depends on Firebase nor reads from it. -In this example, since the `FirebaseUploader`'s `Output` type is `Void`, we simply can call ``BulkExportSession/start(retryFailedBatches:concurrencyLevel:)`` and don't need to do anything beyond that. +In this example the `FirebaseUploader`'s outputs are receipts its own `didPersist` releases, so we simply call ``BulkExportSession/start(retryFailedBatches:concurrencyLevel:)`` and need nothing beyond that. @@ -100,18 +102,30 @@ extension BulkExportSessionIdentifier { } struct FHIREncodedJSONExporter: BatchProcessor { - let contextForSample: @Sendable (HKSample) throws -> HealthKitConversionContext + /// One batch's file of graphs, and the receipt to release once the session recorded the batch. + struct ExportedFile: Sendable { + let url: URL + let receipt: HealthKitFHIRExporter.Receipt + } + + let exporter: HealthKitFHIRExporter - func process(_ samples: consuming [Sample], of sampleType: SampleType) throws -> URL { - let healthKitSamples = samples.map { $0 as HKSample } - let result = HealthKitConverter().convert(healthKitSamples, context: contextForSample) - if let failure = result.failures.first { - throw failure + func process(_ samples: consuming [Sample], of sampleType: SampleType) throws -> ExportedFile { + var graphs: [Data] = [] + let receipt = try exporter.export(samples.map { $0 as HKSample }) { export in + if let graph = export.graph { + graphs.append(graph.json) + } } - let encoded = try JSONEncoder().encode(result.conversions.flatMap(\.all).map(\.bundle)) + // A JSON array of the validated graph bytes, spliced verbatim rather than re-encoded. + let file = Data("[".utf8) + graphs.joined(separator: Data(",".utf8)) + Data("]".utf8) let url = URL.temporaryDirectory.appendingPathComponent(UUID().uuidString, conformingTo: .json) - try encoded.write(to: url) - return url + try file.write(to: url) + return ExportedFile(url: url, receipt: receipt) + } + + func didPersist(_ output: ExportedFile) async { + output.receipt.release() } } @@ -120,7 +134,7 @@ let session = try await bulkExporter.session( withId: .backgroundFHIRExport, for: [SampleType.activeEnergyBurned, SampleType.heartRate, SampleType.stepCount], startDate: .oldestSample, - using: FHIREncodedJSONExporter(contextForSample: conversionContext) + using: FHIREncodedJSONExporter(exporter: exporter) ) // start the session @@ -128,13 +142,13 @@ let results = try session.start() // await the results Task { - for await url in results { - // process the JSON file at `url` in some way + for await file in results { + // process the JSON file at `file.url` in some way } } ``` -Since the `FHIREncodedJSONExporter` returns a `URL` (rather than `Void`, as with the `FirebaseUploader`), the ``BulkExportSession/start(retryFailedBatches:concurrencyLevel:)`` function's return type will be an `AsyncStream` which gives us access to the individual batch processing results (in this case the urls of the exported JSON files). +Since the `FHIREncodedJSONExporter` returns an `ExportedFile`, the ``BulkExportSession/start(retryFailedBatches:concurrencyLevel:)`` function's return type will be an `AsyncStream`, which gives us access to the individual batch processing results (in this case the urls of the exported JSON files). ### Pausing and Recovery diff --git a/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/ConfiguringAConversion.md b/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/ConfiguringAConversion.md index 60d500c43..eb9a42893 100644 --- a/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/ConfiguringAConversion.md +++ b/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/ConfiguringAConversion.md @@ -81,7 +81,8 @@ let host = HostDevice.current() ``` `ConverterRole` states how the application relates to the measurement. -`.assembler` is the default; `.gateway` marks the converting application as the one that mediated the measurement, and `.gatewayApplication` names a distinct application that did, emitted as a second application snapshot referenced by `observation-gatewayDevice`. +`.assembler` is the default; `.gateway` marks the converting application as the one that mediated the measurement, and `.gatewayApplication` names a distinct application that did, emitted as a second application snapshot when an Observation references it through `observation-gatewayDevice`. +Recording and clinical documents carry no gateway link under any role. ## Persisting the event identity @@ -119,9 +120,9 @@ FHIR separates when a measurement happened from when a record was published; the This converter keeps the distinct clocks explicit: -- `Observation.effective` is read from each sample's own `HKSample.startDate` and `endDate`, in the sample's own time zone when `HKMetadataKeyTimeZone` names one and in UTC with ``HealthKitConversionWarning/sourceOffsetUnavailable(field:)`` naming each effective element otherwise; a workout's segments follow the workout's zone the same way, and no effective value ever takes the phone's current zone. +- `Observation.effective` is read from each sample's own `HKSample.startDate` and `endDate`, in the sample's own time zone when `HKMetadataKeyTimeZone` names one and in UTC with ``HealthKitConversionWarning/sourceOffsetUnavailable(field:)`` naming each effective element otherwise, and no effective value ever takes the phone's current zone. - `Observation.issued` is absent because HealthKit exposes no object availability/modification instant. -- `Provenance.occurred`, `Provenance.recorded`, and `Bundle.timestamp` take the event's persisted `conversionInstant`, always in UTC, so a retry after the phone changed time zone rebuilds the same bytes. +- `Provenance.occurred`, `Provenance.recorded`, `Bundle.timestamp` and `DocumentReference.date` take the event's persisted `conversionInstant`, always in UTC at millisecond precision with ASCII digits, so a retry after the phone changed time zone or locale rebuilds the same bytes. - A retry reuses that instant; a later source version receives a new event and instant. The converter never reads the clock. diff --git a/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/GroveHealthKitFHIR.md b/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/GroveHealthKitFHIR.md index 995fcf154..c0341d2d0 100644 --- a/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/GroveHealthKitFHIR.md +++ b/Sources/GroveHealthKitFHIR/GroveHealthKitFHIR.docc/GroveHealthKitFHIR.md @@ -146,7 +146,8 @@ let disclosing = HealthKitConversionContext(event: event, options: options) A `RepositoryID` per `ExchangeGraphNode` in `repositoryIDs` gives a graph node the logical id your repository assigned. -`ConverterRole.gatewayApplication` names a distinct application that mediated the measurement; it travels as a second application snapshot. +`ConverterRole.gatewayApplication` names a distinct application that mediated the measurement; it travels as a second application snapshot when an Observation output names it through `observation-gatewayDevice`. +Heartbeat series, workout route, clinical record and CDA graphs state no gateway application. ``HealthKitConversion/warnings`` lists what a graph does not carry although its record did; log them with that graph's event. ``HealthKitConversionSet/warnings`` flattens them over every graph of the set, so an ECG's list includes its symptoms'. diff --git a/Sources/GroveHealthKitFHIR/HealthKitCatalog.swift b/Sources/GroveHealthKitFHIR/HealthKitCatalog.swift index d36259f52..3ddd69c91 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitCatalog.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitCatalog.swift @@ -145,8 +145,11 @@ public enum HealthKitCatalog { /// Every output the converter mints for one source type, in the order the graph emits them. /// - /// A caller holding only a source type — a deletion, whose sample is already gone — names - /// the exact outputs an addition minted. + /// A caller holding only a source type — a deletion, whose sample is already gone — names the outputs an + /// addition minted. One exception: an ECG's average-heart-rate child is listed whether or not the ECG stated an + /// average, so the retraction of an ECG without one also names a child that was never emitted. A deletion cannot + /// tell the two apart, and the pinned guide has no source-record retraction scope yet (an IG gap; a draft + /// exists); a receiver resolves the extra target to nothing. public static func outputs(for type: HealthKitSourceType) -> [HealthKitOutput] { switch type { case .electrocardiogram: diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+Workout.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+Workout.swift index 9bdf7c434..a3cb8dee1 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+Workout.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter+Workout.swift @@ -172,8 +172,7 @@ extension HealthKitConverter { try workoutValue(activityType: workout.workoutActivityType) } - /// The shared and platform codings for one activity type, used by a session and by each of its - /// per-activity segments. + /// The shared and platform codings for one activity type. static func workoutValue(activityType: HKWorkoutActivityType) throws -> CodeableConcept { var codings = [Coding( code: FHIRPrimitive(FHIRString(stringLiteral: sharedWorkoutActivity(activityType))), diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift index aa2f17830..2780df546 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift @@ -8,7 +8,6 @@ #if canImport(HealthKit) -public import Foundation public import GroveFHIRContract public import HealthKit @@ -33,12 +32,20 @@ extension HealthKitFHIRExporter { public var recordingDevice: RecordingDevicePolicy = .localIdentifier /// How the converting application relates to each measurement. See ``RolePolicy``. public var role: RolePolicy = .assembler - /// The only way the clear HealthKit UUID reaches the wire: as an identifier under a system the - /// deployment owns, on the primary output and on retraction targets. + /// Discloses the clear HealthKit UUID as an identifier under a system the deployment owns, on the primary + /// output and on retraction targets. Besides ``LegacyBundleID/healthKitUUID``, which repeats it as + /// `Bundle.id`, this is the only way it reaches the wire. public var nativeIdentifier: GovernedSourceIdentifierDisclosurePolicy = .omit /// Whether a recording Device carries the UDI HealthKit supplies. public var udi: Disclosure = .omit /// Whether a workout route becomes a recording document; a route re-identifies readily. + /// + /// A route deletion is retracted only while this is `.authorized`: retraction follows the policy in force + /// when the deletion is retracted, not the one a route was exported under. Switching from `.authorized` to + /// `.omit` therefore leaves routes exported earlier live at the receiver, and switching to `.authorized` + /// retracts routes deleted afterwards that were never exported, naming nodes the receiver never received. + /// The guide asks a retraction to name the exact prior graph (HealthKit guide `implementation.md`, + /// retracting a source record); keep one route policy for an installation's ledger to keep that true. public var route: Disclosure = .omit /// A deployment that still keys its receiver on `Bundle.id` can keep the old value there for the /// transition. See ``LegacyBundleID``. @@ -121,7 +128,9 @@ extension HealthKitFHIRExporter { case gatewayForOwnWrites /// The converting application mediated every measurement. case gateway - /// A distinct application mediated every measurement; it travels as a second application snapshot. + /// A distinct application mediated every measurement; an Observation names it through + /// `observation-gatewayDevice`, so its graph carries it as a second application snapshot. Recording and + /// clinical documents carry no gateway link under any role, so their graphs state no gateway application. case gatewayApplication(ApplicationDevice) /// The role for one sample under this policy. diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift index 71348f86f..0b03666b2 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift @@ -61,7 +61,8 @@ extension HealthKitFHIRExporter { /// What one record produced: an exchange graph, or the reason it produced none. public struct Export: Sendable { /// The record's coordinate in the HealthKit store. It stays on the device and is never on the wire - /// unless ``Options/nativeIdentifier`` discloses it. + /// unless ``Options/nativeIdentifier`` discloses it, or ``Options/legacyBundleID`` repeats its UUID as + /// `Bundle.id`. public struct Source: Hashable, Sendable { public let uuid: UUID /// The HealthKit type identifier, such as `HKQuantityTypeIdentifierHeartRate`. @@ -76,7 +77,8 @@ extension HealthKitFHIRExporter { /// The record was refused; nothing was emitted and the export continued. Refusals are /// deterministic, so an exact redelivery refuses identically. case refused(HealthKitConversionError) - /// A deletion of a source type that never emits outputs. + /// A deletion that names no output this exporter can have emitted: a source type without outputs, or a + /// workout route while ``Options/route`` is `.omit`. No event is reserved for it. case nothingToRetract } diff --git a/Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark+Support.swift b/Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark+Support.swift index a6cc9de37..eae25f8a9 100644 --- a/Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark+Support.swift +++ b/Tests/GroveHealthKitFHIRTests/ConversionThroughputBenchmark+Support.swift @@ -164,7 +164,8 @@ enum SampleFactory { } } - /// A one-hour run with a pause, a resume, eight laps and two generic segments: twelve segment children. + /// A one-hour run with a pause, a resume, eight laps and two generic segments; the converter withholds these events + /// and exports the session only (the scenario keeps its name so runs stay comparable). static func workouts(count: Int, withEvents: Bool) -> [HKSample] { (0.. Bool { @@ -305,8 +279,9 @@ struct ConversionThroughputBenchmark { } run.report.line("scenario=\(run.name) phase=encode-bundle(sortedKeys+withoutEscapingSlashes) \(run.rate(stagedSeconds)) " + "bytesPerBundle=\(stagedBytes / run.count)") - // The graph's stored bytes are the encoder's bytes, so (b) is exactly what the graph already holds. - #expect(run.conversions[0].graph.json.count == encoded[0].count) + // The graph's stored bytes are the staging encoding (sorted members, unescaped slashes): a consumer that stores + // graph.json verbatim skips that second encode entirely. + #expect(try run.conversions[0].graph.json == stagingEncoder.encode(run.conversions[0].bundle)) run.graphInitSeconds = try Stopwatch.seconds { for conversion in run.conversions { diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift index e45198c85..6f37d5ef5 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift @@ -200,10 +200,12 @@ extension GoldenCase { ) } - /// The sinus-rhythm ECG sample and the validated evidence its voltages would yield, with symptoms present or none. + /// The sinus-rhythm ECG sample and the validated evidence its voltages would yield, with symptoms present or none, + /// and the average heart rate the ECG states, if any. static func electrocardiogramEvidence( uuid ordinal: UInt8, - symptomsPresent: Bool + symptomsPresent: Bool, + averageHeartRate: Double? = 72 ) throws -> (sample: HKElectrocardiogram, evidence: HealthKitECGEvidence) { let ecg = try StoredSampleFixtures.seriesSample( HKElectrocardiogram.self, @@ -221,7 +223,7 @@ extension GoldenCase { classification: .sinusRhythm, symptomsStatus: symptomsPresent ? .present : .none, numberOfVoltageMeasurements: 4, - averageHeartRate: 72, + averageHeartRate: averageHeartRate, samplingFrequency: 500, algorithmVersion: HKAppleECGAlgorithmVersion.version2.rawValue ) diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift index 52dee1643..e347f574d 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift @@ -258,6 +258,32 @@ struct GoldenGraphTests { #expect(provenance.target.compactMap { $0.identifier?.value?.value?.string } == emitted) } + /// The pinned guide has no source-record retraction scope (an IG gap; owner decision: keep): a deletion cannot tell + /// whether an ECG stated an average heart rate, so its retraction always names the child, emitted or not. + @Test + func ecgRetractionNamesTheAverageHeartRateChildAlways() throws { + let (ecg, evidence) = try GoldenCase.electrocardiogramEvidence(uuid: 0xA4, symptomsPresent: false, averageHeartRate: nil) + let context = try GoldenFixtures.context(sequence: 204) + let conversion = try HealthKitConverter.convertECG(ecg, evidence: evidence, symptoms: [], context: context, symptomContexts: []) + #expect(conversion.identifiers.childOutputs.isEmpty, "an ECG without an average emits no child") + let retraction = try HealthKitConverter().retraction( + for: HealthKitSourceRecord(uuid: ecg.uuid, type: .electrocardiogram), + context: GoldenFixtures.context(sequence: 205), + occurred: .instant(GoldenFixtures.conversionInstant) + ) + let provenance = try #require(retraction.graph.bundle.entry?.compactMap { $0.resource?.get(if: Provenance.self) }.first) + let child = try context.identityScope + .sourceRecord( + adapterID: HealthKitConverter.adapterID, + sourceType: HealthKitSourceType.electrocardiogram.rawValue, + repositoryScope: context.repositoryScope, + nativeRecordID: ecg.uuid.uuidString.lowercased() + ) + .output(role: "average-heart-rate", discriminator: "single") + let targets = provenance.target.compactMap { $0.identifier?.value?.value?.string } + #expect(targets == [conversion.identifiers.primaryOutput.identifier.value, child.identifier.value]) + } + /// A writer classified as an application whose bundle identifier is not one is a refusal; a writer with a blank /// name is merely no writer (`writer-blank-name-with-sync-identity` pins that graph). @Test From fa894bb0efdd76c934239e21891df8e813d6b556 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 17:31:13 +0200 Subject: [PATCH 035/220] Check Every Golden's Reported Source and Source Artifact Against Its Graph Fix-round step G3 review, audit ledger section 1 finding 5 (identifiers and source never compared): two holes left after e8703742 and 9b2e2d54. - The exporter lane recorded each export's source but never compared it: GoldenOutput(_ export:) sets no identifiers, and reportMismatches returned nothing without them, so all exporter goldens skipped the check. A reported source is now checked on every graph that has one, against the record the graph's Provenance source entity names (one source entity whose identifier is the identity minted from the reported type and UUID). That covers the exporter lane and its retraction too. An export reporting a type outside the inventory now fails the case instead of silently reporting no source. - The source-artifact check passed when the assembler reported no artifact (carries(_, nil) was true). The primary output must now carry exactly the reported source-artifact identity: none when none is reported, and that one otherwise. Output unchanged; tests only. Mutation proof (each applied alone, full GroveHealthKitFHIRTests on macOS, then reverted; both survived 2a9f5ef1 at 289 passed, 1 skipped): - X1, HealthKitFHIRExporter.swift: every graph of a set reports the record's typeIdentifier (Export.Source(uuid: conversion.source.uuid, typeIdentifier: plan.source.typeIdentifier)): fails matchesCheckedInGolden for exporter-deployment-electrocardiogram-symptom with ["source"]. - RM3, ExchangeGraphAssembler.swift: sourceArtifact: nil: fails matchesCheckedInGolden for clinical-document, heartbeat-series and workout-route with ["source artifact"]. Co-Authored-By: Claude Opus 5.5 --- .../GoldenGraphCases+Exporter.swift | 8 +- .../GoldenGraphFixtures.swift | 82 ++++++++++++------- 2 files changed, 60 insertions(+), 30 deletions(-) diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Exporter.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Exporter.swift index 12e7baee5..b36c62b38 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Exporter.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Exporter.swift @@ -193,15 +193,19 @@ extension GoldenCase { extension GoldenOutput { - /// What one export delivered: its graph and, as the outline spells them, the diagnostics it reported. + /// What one export delivered: its graph, the record it reported the graph for, which the golden test checks + /// against the graph's source identity, and, as the outline spells them, the diagnostics it reported. init(_ export: HealthKitFHIRExporter.Export) throws { guard let graph = export.graph else { throw GoldenCaseError.notExported(String(describing: export.outcome)) } + guard let type = export.source.sourceType else { + throw GoldenCaseError.notExported("a graph reported for the unregistered type \(export.source.typeIdentifier)") + } self.init( graph: graph, renderedWarnings: export.warnings.map { "\($0.code)@\($0.location)" }, - source: export.source.sourceType.map { HealthKitSourceRecord(uuid: export.source.uuid, type: $0) }, + source: HealthKitSourceRecord(uuid: export.source.uuid, type: type), identifiers: nil ) } diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift index bcf792fc2..1a4b96c43 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphFixtures.swift @@ -22,7 +22,7 @@ struct GoldenOutput: Sendable { let graph: ExchangeGraph /// Each warning as the outline spells it: the registry code, then the field, device name or keys it names. let renderedWarnings: [String] - /// The record the conversion names; `nil` for a retraction, which names its record through its targets. + /// The record the API reported the graph for; `nil` for a converter retraction, which reports none. let source: HealthKitSourceRecord? /// The identities the conversion reported; `nil` where the API reports none. let identifiers: ExchangeGraphIdentifiers? @@ -298,27 +298,58 @@ enum GoldenFixtures { extension GoldenOutput { - /// Where what the conversion reported disagrees with the graph it reported it for, read from the graph's own - /// tokens: each reported output and Device is the entry its fullUrl names and carries that identity, the - /// Provenance is the one entry at its entry-node fullUrl, the source record and artifact identities are on the - /// primary output, every output and Device entry is reported (a distinct gateway application aside, which no - /// identity names), and the source is the record the graph's source identity is minted from. Empty for a + /// An identifier as the system and value its identity rests on. + private static func key(_ identifier: LosslessJSONValue?) -> String { + "\(identifier?["system"]?.text ?? "")|\(identifier?["value"]?.text ?? "")" + } + + private static func key(_ identity: RoledIdentifier) -> String { + "\(identity.identifier.system.rawValue)|\(identity.identifier.value)" + } + + /// Where what the API reported disagrees with the graph it reported it for, read from the graph's own tokens. + /// + /// A reported source is the record the Provenance's source entity names; an export reports one for its + /// retractions too. Reported identities: each output and Device is the entry its fullUrl names and carries that + /// identity, the Provenance is the one entry at its entry-node fullUrl, the primary output carries the source + /// record identity minted from the source and exactly the reported source-artifact identity, and every output and + /// Device entry is reported (a distinct gateway application aside, which no identity names). Empty for a converter /// retraction, which reports neither. func reportMismatches(identityScope: OpaqueIdentityScope, repositoryScope: BusinessIdentifier) throws -> [String] { - guard let identifiers, let source else { - return [] - } let entries: [LosslessJSONValue] = try LosslessJSONValue(parsing: graph.json)["entry"]?.elements ?? [] + let minted = try source.map { source in + try identityScope.sourceRecord( + adapterID: HealthKitConverter.adapterID, + sourceType: source.type.rawValue, + repositoryScope: repositoryScope, + nativeRecordID: source.uuid.uuidString.lowercased() + ).identifier + } + var mismatches: [String] = [] + let sourceEntities = entries + .filter { $0["resource"]?["resourceType"]?.text == "Provenance" } + .flatMap { $0["resource"]?["entity"]?.elements ?? [] } + .filter { $0["role"]?.text == "source" } + if let minted, sourceEntities.map({ Self.key($0["what"]?["identifier"]) }) != [Self.key(minted)] { + mismatches.append("source") + } + guard let identifiers else { + return mismatches + } + if minted != identifiers.sourceRecord { + mismatches.append("source record identity") + } + return mismatches + (try identityMismatches(identifiers, entries: entries)) + } + + /// Where the reported identities disagree with the graph's entries. + private func identityMismatches(_ identifiers: ExchangeGraphIdentifiers, entries: [LosslessJSONValue]) throws -> [String] { var byURL: [String: LosslessJSONValue] = [:] for entry in entries { byURL[entry["fullUrl"]?.text ?? ""] = entry } - func carries(_ url: String, _ identity: RoledIdentifier?) -> Bool { - guard let identity else { - return true - } - let stated: [LosslessJSONValue] = byURL[url]?["resource"]?["identifier"]?.elements ?? [] - return stated.contains { $0["system"]?.text == identity.identifier.system.rawValue && $0["value"]?.text == identity.identifier.value } + func stated(_ url: String) -> [LosslessJSONValue] { + byURL[url]?["resource"]?["identifier"]?.elements ?? [] } func urls(ofTypes types: Set) -> Set { Set(entries.filter { types.contains($0["resource"]?["resourceType"]?.text ?? "") }.compactMap { $0["fullUrl"]?.text }) @@ -329,19 +360,23 @@ extension GoldenOutput { let devices: [RoledIdentifier] = [identifiers.applicationSnapshot, identifiers.hostSnapshot] + optionalDevices let outputs: [RoledIdentifier] = [identifiers.primaryOutput] + identifiers.childOutputs var mismatches: [String] = [] - for node in outputs + devices where !carries(try node.fullURLString, node) { + for node in outputs + devices where !stated(try node.fullURLString).contains(where: { Self.key($0) == Self.key(node) }) { mismatches.append("node \(node.identifier.value)") } // A Provenance carries no identifier; its entry-node key is its fullUrl. if urls(ofTypes: ["Provenance"]) != [try identifiers.provenance.fullURLString] { mismatches.append("provenance") } - let primaryURL = try identifiers.primaryOutput.fullURLString if identifiers.event != graph.eventIdentifier.identifier { mismatches.append("event") } - if !carries(primaryURL, identifiers.sourceRecord) || !carries(primaryURL, identifiers.sourceArtifact) { - mismatches.append("source record or artifact identity") + let primary = stated(try identifiers.primaryOutput.fullURLString) + if !primary.contains(where: { Self.key($0) == Self.key(identifiers.sourceRecord) }) { + mismatches.append("source record on the primary output") + } + let artifacts = primary.filter { $0["type"]?["coding"]?.elements?.first?["code"]?.text == GroveIdentifierRole.sourceArtifact.rawValue } + if artifacts.map({ Self.key($0) }) != [identifiers.sourceArtifact].compactMap(\.self).map({ Self.key($0) }) { + mismatches.append("source artifact") } if urls(ofTypes: ["Observation", "DocumentReference"]) != Set(try outputs.map { try $0.fullURLString }) { mismatches.append("outputs") @@ -353,15 +388,6 @@ extension GoldenOutput { if urls(ofTypes: ["Device"]).subtracting(gatewayURLs.subtracting(deviceURLs)) != deviceURLs { mismatches.append("devices") } - let minted = try identityScope.sourceRecord( - adapterID: HealthKitConverter.adapterID, - sourceType: source.type.rawValue, - repositoryScope: repositoryScope, - nativeRecordID: source.uuid.uuidString.lowercased() - ) - if minted.identifier != identifiers.sourceRecord { - mismatches.append("source") - } return mismatches } } From f0472336edcea91096bfa20418dca2c3cdc04e0d Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 17:31:23 +0200 Subject: [PATCH 036/220] Pin the Retraction Instants No FHIR DateTime Can State Fix-round step G3 review, audit ledger section 5 finding 1 (F7 part): the F7 spec's boundary tests (F7-instants.md, New tests, "boundaries") were not added. A regression that writes a 0001-01-01 sentinel instead of refusing therefore passed the whole suite. ExchangeEnvelopeFixTests: - retractionRefusesUnstatableInstants builds RetractionEvent directly, through the public contract API that outlives the deprecated converter. `.instant(.distantPast)`, `.instant(year 10000)`, a period ending at `.distantPast` or in year 10000, and a context recorded at `.distantPast` each throw RetractionEventError.invalidInstant. A period starting at `.distantPast` is still accepted (the agreed clamp). - eventInstantsAreMilliseconds: the deprecated converter refuses an event at `.distantPast` as HealthKitConversionError.dependency. Output unchanged; tests only. Mutation proof (each applied alone, full GroveHealthKitFHIRTests on macOS, then reverted): - RetractionEvent.occurredX clamps `.instant(date)` and the period end to ExchangeInstant.earliestStatable (the review's mutation; it survived 2a9f5ef1 at 289 passed, 1 skipped): fails retractionRefusesUnstatableInstants (`.instant(0001-01-01)` accepted). - only the period end clamped: fails it (`.period(nil, 0001-01-01)`). - recorded clamped to earliestStatable: fails it ("recorded before year 1"). - ExchangeGraphAssembler clamps draft.instant for Bundle.timestamp and the Provenance instants: fails eventInstantsAreMilliseconds. Co-Authored-By: Claude Opus 5.5 --- .../ExchangeEnvelopeFixTests.swift | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/Tests/GroveHealthKitFHIRTests/ExchangeEnvelopeFixTests.swift b/Tests/GroveHealthKitFHIRTests/ExchangeEnvelopeFixTests.swift index 6002c0b60..551a88257 100644 --- a/Tests/GroveHealthKitFHIRTests/ExchangeEnvelopeFixTests.swift +++ b/Tests/GroveHealthKitFHIRTests/ExchangeEnvelopeFixTests.swift @@ -133,6 +133,15 @@ struct ExchangeEnvelopeFixTests { return } #expect(occurred.value?.description == "2026-08-17T23:30:00.251Z") + // No FHIR instant states an event before year 1: the conversion is refused, never written as a sentinel. + let unstatable = HealthKitConversionContext(event: .test(conversionInstant: .distantPast)) + let refusal = #expect(throws: HealthKitConversionError.self) { + try HealthKitConverter().convert(try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(92)), context: unstatable) + } + guard case .dependency? = refusal else { + Issue.record("An unstatable event instant is a dependency refusal, not \(String(describing: refusal))") + return + } } @Test("A retraction states its bounds and its recording in UTC at millisecond precision, and a start before year 1 as year 1") @@ -168,6 +177,35 @@ struct ExchangeEnvelopeFixTests { #expect(clamped.start?.value?.description == "0001-01-01T00:00:00Z") } + /// No FHIR dateTime states an instant before year 1 or from year 10000 on. Only a period's start is clamped, as a + /// lower bound stays true; a retraction refuses any other such occurrence or recording rather than write a sentinel. + @Test("A retraction refuses an occurrence or a recording no FHIR dateTime can state") + func retractionRefusesUnstatableInstants() throws { + let record = try Self.base.identityScope.sourceRecord( + adapterID: HealthKitConverter.adapterID, + sourceType: HealthKitSourceType.heartRate.rawValue, + repositoryScope: Self.base.repositoryScope, + nativeRecordID: GoldenFixtures.uuid(96).uuidString.lowercased() + ) + let target = try RetractionTarget(identifier: record.output(role: "primary", discriminator: "0"), resourceType: .observation, role: .primaryOutput) + func retraction(_ occurred: RetractionOccurrence, recordedAt: Date = GoldenFixtures.conversionInstant) throws { + _ = try RetractionEvent(targets: [target], context: .test(conversionInstant: recordedAt), sourceRecord: record.identifier, occurred: occurred) + } + let yearTenThousand = Date(timeIntervalSince1970: 253_402_300_800) + let unstatable: [RetractionOccurrence] = [ + .instant(.distantPast), .instant(yearTenThousand), .period(start: nil, end: .distantPast), .period(start: nil, end: yearTenThousand) + ] + for occurred in unstatable { + #expect(throws: RetractionEventError.invalidInstant, "occurred \(occurred)") { + try retraction(occurred) + } + } + #expect(throws: RetractionEventError.invalidInstant, "recorded before year 1") { + try retraction(.instant(GoldenFixtures.conversionInstant), recordedAt: .distantPast) + } + try retraction(.period(start: .distantPast, end: GoldenFixtures.conversionInstant)) + } + @Test("A document's date is the event instant in UTC at millisecond precision") @available(*, deprecated, message: "Exercises the deprecated converter's document path") func documentDateIsMilliseconds() throws { From 57c4f5373440492aadb127f54cbf2a8267d8b340 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 17:31:37 +0200 Subject: [PATCH 037/220] Pin the Exporter's UDI Option, Sub-Second Periods and Each Offset Omission Once Fix-round step G3 review: three regressions the suite still let through. - Audit ledger section 1 finding 2 (the exporter's option mapping is unpinned): Options.udi reached no test. policiesApply authorizes UDI only beside recordingDevice .omit, so no Device can carry one. HealthKitFHIRExporterTests.udiFollowsItsOption exports the golden watch (local identifier and UDI) under `.authorized` and `.omit`: the recording Device states udiCarrier (01)00844588003288 only under `.authorized`. - Section 1 finding 1, survivor M5 on the Period branch: only the dateTime branch had a sub-second fixture. effectivePeriodKeepsMilliseconds exports a step count from .2514 s to 60.7496 s past the golden start in Los Angeles. Its effectivePeriod is 2026-08-17T15:30:00.251-07:00 to 2026-08-17T15:31:00.750-07:00. - Envelope lens, pre-existing: nothing pinned that sourceOffsetWarnings names each field once. An ECG without a time zone states two Period outputs, the ECG and its average-heart-rate child. electrocardiogramReportsEachOffsetOmissionOnce (exporter record tests) exports one through the evidence seam. It delivers both Observations and exactly mobile-omission.source-offset at Observation.effectivePeriod.start and .end, each once. The ECG evidence fixture gains `timeZoned` (default true). Its evidence now reads the time zone from the sample's metadata, as ecgSourceEvidence does, so the fixture's evidence and metadata cannot state different zones. The golden time zone resolves to the same TimeZone, so every ECG golden is unchanged. Output unchanged; tests only. Mutation proof (each applied alone, full GroveHealthKitFHIRTests on macOS, then reverted; X2, M5b and H1 survived 2a9f5ef1 at 289 passed, 1 skipped): - X2, HealthKitFHIRExporter.swift: udiDisclosure: .omit: fails udiFollowsItsOption. - M5b, HealthKitConverter+Observation.swift: the Period start truncated to whole seconds: fails effectivePeriodKeepsMilliseconds (start ...15:30:00-07:00). The same on the end: fails it (end ...15:31:00-07:00). - H1, HealthKitAssembly.swift: `fields += elements` (no dedupe): fails electrocardiogramReportsEachOffsetOmissionOnce (four warnings). Co-Authored-By: Claude Opus 5.5 --- .../GoldenGraphCases+Documents.swift | 20 +++++------ .../HealthKitFHIRExporterRecordTests.swift | 14 ++++++++ .../HealthKitFHIRExporterTests.swift | 33 +++++++++++++++++++ 3 files changed, 55 insertions(+), 12 deletions(-) diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift index 6f37d5ef5..77b73ca73 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift @@ -19,7 +19,6 @@ import ModelsR4 enum GoldenCaseError: Error { case unexpectedCompanions(Int) case routeOmitted - case unknownTimeZone(String) case notExported(String) } @@ -201,25 +200,22 @@ extension GoldenCase { } /// The sinus-rhythm ECG sample and the validated evidence its voltages would yield, with symptoms present or none, - /// and the average heart rate the ECG states, if any. + /// and the average heart rate the ECG states, if any. The sample's metadata states the golden time zone unless + /// `timeZoned` is false; the evidence reads it from there, as the public path does. static func electrocardiogramEvidence( uuid ordinal: UInt8, symptomsPresent: Bool, - averageHeartRate: Double? = 72 + averageHeartRate: Double? = 72, + timeZoned: Bool = true ) throws -> (sample: HKElectrocardiogram, evidence: HealthKitECGEvidence) { - let ecg = try StoredSampleFixtures.seriesSample( - HKElectrocardiogram.self, - sampleType: HKObjectType.electrocardiogramType(), - shape: seriesShape(uuid: ordinal, duration: 30) - ) - guard let timeZone = TimeZone(identifier: GoldenFixtures.timeZone) else { - throw GoldenCaseError.unknownTimeZone(GoldenFixtures.timeZone) - } + var shape = seriesShape(uuid: ordinal, duration: 30) + shape.metadata = timeZoned ? shape.metadata : [:] + let ecg = try StoredSampleFixtures.seriesSample(HKElectrocardiogram.self, sampleType: HKObjectType.electrocardiogramType(), shape: shape) let source = HealthKitECGSourceEvidence( sourceTypeIdentifier: HealthKitContract.electrocardiogramSourceTypeIdentifier, startDate: GoldenFixtures.sampleStart, endDate: GoldenFixtures.sampleStart.addingTimeInterval(30), - timeZone: timeZone, + timeZone: try HealthKitConverter.healthKitTimeZone(for: ecg), classification: .sinusRhythm, symptomsStatus: symptomsPresent ? .present : .none, numberOfVoltageMeasurements: 4, diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterRecordTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterRecordTests.swift index 427573123..ba30a9104 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterRecordTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterRecordTests.swift @@ -13,6 +13,7 @@ import Foundation @testable import GroveFHIRContract @testable import GroveHealthKitFHIR import HealthKit +import ModelsR4 import Testing @@ -148,6 +149,19 @@ struct HealthKitFHIRExporterRecordTests { } #expect(reason == .ecgEvidence(.duplicateSymptomSource(symptom.uuid))) } + + /// The ECG and its average-heart-rate child both state an effective Period; the omission names each field once. + @Test("An ECG without a time zone reports each effective field it states in UTC once, though its child states them too") + func electrocardiogramReportsEachOffsetOmissionOnce() throws { + let (ecg, evidence) = try GoldenCase.electrocardiogramEvidence(uuid: 0xE8, symptomsPresent: false, timeZoned: false) + let (exports, _) = try Fixtures.collect(Fixtures.exporter(), [.electrocardiogramEvidence(ecg, evidence: evidence, symptoms: [])]) + try #require(exports.count == 1) + let observations = exports[0].graph?.bundle.entry?.compactMap { $0.resource?.get(if: Observation.self) } ?? [] + #expect(observations.count == 2, "the ECG and its average heart rate") + #expect(exports[0].warnings == ["Observation.effectivePeriod.start", "Observation.effectivePeriod.end"].map { + ExchangeGraphRule.mobileOmissionSourceOffset.diagnostic(at: $0) + }) + } } #endif diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift index 00bf3db46..0c9e1d900 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift @@ -178,6 +178,39 @@ struct HealthKitFHIRExporterTests { #expect(bundle == expected) } + @Test("The UDI an HKDevice supplies reaches its recording Device only under Options.udi .authorized") + func udiFollowsItsOption() throws { + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(13), device: GoldenFixtures.watch) + func carriedUDIs(_ udi: HealthKitFHIRExporter.Disclosure) throws -> [String] { + let (exports, _) = try Self.collect(Self.exporter { $0.udi = udi }, [sample]) + let devices = exports.first?.graph?.bundle.entry?.compactMap { $0.resource?.get(if: Device.self) } ?? [] + return devices.flatMap { $0.udiCarrier ?? [] }.compactMap { $0.deviceIdentifier?.value?.string } + } + #expect(try carriedUDIs(.authorized) == ["(01)00844588003288"]) + #expect(try carriedUDIs(.omit).isEmpty) + } + + @Test("Both bounds of an effective Period keep their milliseconds in the source's offset") + func effectivePeriodKeepsMilliseconds() throws { + let start = GoldenFixtures.sampleStart.addingTimeInterval(0.2514) + let steps = HKQuantitySample( + type: HKQuantityType(.stepCount), + quantity: HKQuantity(unit: .count(), doubleValue: 120), + start: start, + end: start.addingTimeInterval(60.4982), + metadata: GoldenFixtures.timeZoneMetadata + ) + let sample = try StoredSampleFixtures.stored(steps, uuid: GoldenFixtures.uuid(14)) + let (exports, _) = try Self.collect(Self.exporter(), [sample]) + let observation = try #require(exports.first?.graph?.bundle.entry?.compactMap { $0.resource?.get(if: Observation.self) }.first) + guard case .period(let period)? = observation.effective else { + Issue.record("A step count is effective over a Period") + return + } + #expect(period.start?.value?.description == "2026-08-17T15:30:00.251-07:00") + #expect(period.end?.value?.description == "2026-08-17T15:31:00.750-07:00") + } + @Test("A native identifier under a deployment system is refused at configuration") func reservedNativeIdentifierSystemIsRefused() throws { let system = Self.base.identityScope.systems.opaque.sourceRecord From c00b3fe637a944b14e0786955ee88e98f0debdf8 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 17:32:09 +0200 Subject: [PATCH 038/220] Pin the Kit's Diagnostics for a Doubly Typed Data Origin and a Leading Foreign Target Fix-round step G3 review, audit ledger section 5 findings 1 (F11 part) and 7. Two behaviours had no vector: - 727f062c's Health Connect data-origin rule requires the one agent to be typed enterer and nothing else. Nothing pinned the "nothing else" half, so a relaxation to `contains("enterer")` would silently diverge from the pinned kit. - The F11 spec's second T3 variant (the source-neutral output targeted at /entry/3/resource/target/0, F11-validator-reverse.md:173-178) was missing. AdapterProvenanceGraphTests gains three vectors, each kit-verified by running exchange_bundle_diagnostics on the same edit of heart-rate-minimal (ig-pin, read-only, PYTHONDONTWRITEBYTECODE=1): - one agent typed enterer and author: health-connect-provenance .data-origin-agent @ Provenance.entity[0].agent[0].who (the kit gives the same for author before enterer); - one agent typed enterer twice: the same diagnostic and location; - the source-neutral output targeted first: mobile-exchange .adapter-provenance-graph @ Provenance.target. The kit accepts the adapter-claimed output at target/0. participant(_:) takes its codes as a list, and appendOutput takes the target's index. Output unchanged; tests only. Mutation proof (each applied alone, full GroveHealthKitFHIRTests on macOS, then reverted): - P1, ExchangeGraph+Profiles.swift: `participantCodes.contains("enterer")` (it survived 2a9f5ef1 at 289 passed, 1 skipped): fails reportsWhatTheKitReports for both new data-origin vectors. - `Set(participantCodes) == ["enterer"]`: fails it for "typed enterer twice". - the graph rule compares only the trailing targets (`Set(provenance.target.suffix(group.fullURLs.count)...)`): fails it for "targeted first" alone. The appended variant cannot tell the difference. Co-Authored-By: Claude Opus 5.5 --- .../AdapterProvenanceGraphTests.swift | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/Tests/GroveHealthKitFHIRTests/AdapterProvenanceGraphTests.swift b/Tests/GroveHealthKitFHIRTests/AdapterProvenanceGraphTests.swift index 7bcd31077..fb74578ae 100644 --- a/Tests/GroveHealthKitFHIRTests/AdapterProvenanceGraphTests.swift +++ b/Tests/GroveHealthKitFHIRTests/AdapterProvenanceGraphTests.swift @@ -62,6 +62,9 @@ struct AdapterProvenanceGraphTests { Vector("a target outside the adapter's outputs", golden: "heart-rate-minimal", expected: (graphRule, "Provenance.target")) { bundle in try appendOutput(to: &bundle, adapterClaimed: false) }, + Vector("a target outside the adapter's outputs, targeted first", golden: "heart-rate-minimal", expected: (graphRule, "Provenance.target")) { bundle in + try appendOutput(to: &bundle, adapterClaimed: false, targetIndex: 0) + }, Vector("a second adapter output of the record, targeted", golden: "heart-rate-minimal", expected: nil) { bundle in try appendOutput(to: &bundle, adapterClaimed: true) }, @@ -89,23 +92,27 @@ struct AdapterProvenanceGraphTests { dataOrigin("an author agent", golden: "writer-foreign-application", agents: nil, at: ".agent[0].who"), dataOrigin("an enterer under another system", agents: { _ in [enterer(system: "https://grovealliance.org/fhir/testing/identifiers/package")] }, at: ".agent[0].who.identifier"), dataOrigin("an enterer with a blank package name", agents: { _ in [enterer(value: " ")] }, at: ".agent[0].who.identifier"), - dataOrigin("an enterer and an author", agents: { converter in [enterer(), ["type": participant("author"), "who": ["reference": converter]]] }, at: ".agent"), - dataOrigin("an enterer referencing a Device", agents: { converter in [["type": participant("enterer"), "who": ["reference": converter, "type": "Device"]]] }, at: ".agent[0].who"), + dataOrigin("an enterer and an author", agents: { converter in [enterer(), ["type": participant(["author"]), "who": ["reference": converter]]] }, at: ".agent"), + dataOrigin("an agent typed enterer and author", agents: { _ in [enterer(typedAs: ["enterer", "author"])] }, at: ".agent[0].who"), + dataOrigin("an agent typed enterer twice", agents: { _ in [enterer(typedAs: ["enterer", "enterer"])] }, at: ".agent[0].who"), + dataOrigin("an enterer referencing a Device", agents: { converter in [["type": participant(["enterer"]), "who": ["reference": converter, "type": "Device"]]] }, at: ".agent[0].who"), // A complete data origin passes the rule; the HealthKit outputs then fail the graph rule. Vector("a complete data origin over HealthKit outputs", golden: "heart-rate-minimal", expected: (graphRule, "Bundle.entry")) { bundle in try governedByHealthConnect(&bundle) { _ in [enterer()] } } ] - private static func participant(_ code: String) -> [String: Any] { - ["coding": [["system": "http://terminology.hl7.org/CodeSystem/provenance-participant-type", "code": code]]] + /// A participant type coded once per code, in order. + private static func participant(_ codes: [String]) -> [String: Any] { + ["coding": codes.map { ["system": "http://terminology.hl7.org/CodeSystem/provenance-participant-type", "code": $0] }] } private static func enterer( system: String = "https://grovealliance.org/fhir/health-connect/NamingSystem/android-package-name", - value: String = "com.example.scale" + value: String = "com.example.scale", + typedAs codes: [String] = ["enterer"] ) -> [String: Any] { - ["type": participant("enterer"), "who": ["type": "Device", "identifier": ["system": system, "value": value]]] + ["type": participant(codes), "who": ["type": "Device", "identifier": ["system": system, "value": value]]] } private static func dataOrigin( @@ -153,8 +160,9 @@ struct AdapterProvenanceGraphTests { } /// Adds a copy of entry 0 as a second output of the same record, under a new source-output identity and the - /// fullUrl it keys, claiming the HealthKit adapter or only its source-neutral profile, and targets it. - private static func appendOutput(to bundle: inout [String: Any], adapterClaimed: Bool) throws { + /// fullUrl it keys, claiming the HealthKit adapter or only its source-neutral profile, and targets it at + /// `targetIndex`, by default after the existing targets. + private static func appendOutput(to bundle: inout [String: Any], adapterClaimed: Bool, targetIndex: Int? = nil) throws { var entries = try #require(bundle["entry"] as? [[String: Any]]) var output = entries[0] let identity = try #require(entries[0]["extension"] as? [[String: Any]]).first?["valueIdentifier"] as? [String: Any] @@ -174,8 +182,9 @@ struct AdapterProvenanceGraphTests { } entries.append(output) try edit(&entries[3], member: "resource") { provenance in - let targets = try #require(provenance["target"] as? [[String: Any]]) - provenance["target"] = targets + [["reference": fullURL]] + var targets = try #require(provenance["target"] as? [[String: Any]]) + targets.insert(["reference": fullURL], at: targetIndex ?? targets.count) + provenance["target"] = targets } bundle["entry"] = entries } From 9f779828ca3d649575697a20d200d0528e434fe8 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 17:32:22 +0200 Subject: [PATCH 039/220] Pin an Apple Per-Device Source Without a Unit Token in Bytes Fix-round step G3 review, G2 leftover (W1 in bytes, final-spec (f) W1). exporter-default-apple-watch-heart-rate pinned only the direction where the HKDevice names its unit. W1 also promises no recording Device without an HKDevice token, and the omission warning when an HKDevice was declined. That direction was pinned only by unit tests. New exporter golden exporter-default-apple-watch-heart-rate-without-unit-token (sequence 109): Options() on a heart rate from the same per-device source (com.apple.health., "Lukas's Apple Watch") whose HKDevice is GoldenFixtures.watchWithoutUnitToken. The graph holds the Observation, the host and application snapshots and the Provenance. There is no recording Device, writer or author. The outline warning is mobile-omission.recording-device@Observation.device. - G17: a new row (assembler 1, healthKit 2, the current revisions, no bump). The outlines.json row takes its new digest, and the file only gains this entry. - HL7 conformance lane: the golden is in ConformanceFixtureTests' validated set. Output diff: none. The goldens were regenerated outside the worktree, and all 55 other files are byte-identical. The new golden is the only addition. Mutation proof (each applied alone, full GroveHealthKitFHIRTests on macOS, then reverted): - the omission warning dropped (HealthKitAssembly+SourceFacts.swift): fails matchesCheckedInGolden for the new golden (its outline), beside heart-rate-device-without-unit-token and four unit tests. - HealthKitLocalIdentifierResolver takes the HKDevice model as the unit token when no local identifier is stated: fails it for the new golden, beside heart-rate-device-without-unit-token and six unit tests. Gates: Scripts/validate-fhir-conformance.sh healthkit against g3-ig (the G3 clone of ig-pin with mobile, sensor and healthkit built, GROVE_FHIR_REF 918f16cd): "Validated 43 producer resource(s) against FHIR R4", "OK - all healthkit resources conform to their declared R4 profiles". Co-Authored-By: Claude Opus 5.5 --- .../ConformanceFixtureTests.swift | 1 + .../GoldenGraphCases+Exporter.swift | 9 + .../GoldenOutputRevisionTests.swift | 3 +- ...e-watch-heart-rate-without-unit-token.json | 350 ++++++++++++++++++ .../Resources/Goldens/outlines.json | 49 +++ 5 files changed, 411 insertions(+), 1 deletion(-) create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-default-apple-watch-heart-rate-without-unit-token.json diff --git a/Tests/GroveHealthKitFHIRTests/ConformanceFixtureTests.swift b/Tests/GroveHealthKitFHIRTests/ConformanceFixtureTests.swift index 404c1d8bf..781ab8351 100644 --- a/Tests/GroveHealthKitFHIRTests/ConformanceFixtureTests.swift +++ b/Tests/GroveHealthKitFHIRTests/ConformanceFixtureTests.swift @@ -91,6 +91,7 @@ struct ConformanceFixtureTests { "writer-non-ascii-name", "gad7-assessment", "exporter-default-apple-watch-heart-rate", + "exporter-default-apple-watch-heart-rate-without-unit-token", "exporter-deployment-own-heart-rate", "exporter-deployment-electrocardiogram", "exporter-deployment-electrocardiogram-symptom", diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Exporter.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Exporter.swift index b36c62b38..9520730ef 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Exporter.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Exporter.swift @@ -124,6 +124,15 @@ extension GoldenCase { let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0xB0), device: GoldenFixtures.watch, writer: ExporterGolden.watchSource) return try ExporterGolden.output(of: [.record(.sample(sample))], sequence: sequence, deployment: false) }, + // The same source whose HKDevice names no unit: no recording Device at all, and that omission reported. + GoldenCase("exporter-default-apple-watch-heart-rate-without-unit-token", sequence: 109) { sequence in + let sample = try GoldenFixtures.heartRate( + uuid: GoldenFixtures.uuid(0xBB), + device: GoldenFixtures.watchWithoutUnitToken, + writer: ExporterGolden.watchSource + ) + return try ExporterGolden.output(of: [.record(.sample(sample))], sequence: sequence, deployment: false) + }, // The deployment's own write in the build that runs, starting at a sub-second instant: its gateway role, // its classified writer, the disclosed UUID, the legacy Bundle.id and the study context. GoldenCase("exporter-deployment-own-heart-rate", sequence: 101) { sequence in diff --git a/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift b/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift index 73151d975..ff8507db4 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift @@ -54,6 +54,7 @@ struct GoldenOutputRevisionTests { GoldenRevision("exporter-clinical-record-dstu2", digest: "9U3i57-PMHal6ADvTYRUUuffIO_5pDB2kB20U_nzX1g", assembler: 1, healthKit: 2), GoldenRevision("exporter-clinical-record-r4", digest: "fLwKd9npbWfEncV49t-W0T8TUVGFh5pjZaHMVZfv7kg", assembler: 1, healthKit: 2), GoldenRevision("exporter-default-apple-watch-heart-rate", digest: "InGqi5S9GIR-Xqk9CltCUCExrkoBf4tOnBJguLfbVUk", assembler: 1, healthKit: 2), + GoldenRevision("exporter-default-apple-watch-heart-rate-without-unit-token", digest: "dIRZm-YxyuXejvh3w44cmoYqVIfw2l-cPbmlZon8W-w", assembler: 1, healthKit: 2), GoldenRevision("exporter-deployment-blood-pressure", digest: "Aq5rL8UXjvLTTQsgor4mTWY-5VIutrJamQ7chv_uRyI", assembler: 1, healthKit: 2), GoldenRevision("exporter-deployment-electrocardiogram", digest: "3GLqhvS12BlRLJ9ETVd1qV5crlxD8TPRCvCCW1tFDUA", assembler: 1, healthKit: 2), GoldenRevision("exporter-deployment-electrocardiogram-symptom", digest: "W-CoOf3DL1ofEW_sGj2nCqAi51UX9lV8t70zVrisgdk", assembler: 1, healthKit: 2), @@ -73,7 +74,7 @@ struct GoldenOutputRevisionTests { GoldenRevision("heartbeat-series", digest: "fB3bdqSnBH2vJxBfzQQDFFeItPoT6Bs8Yom7uFbYS98", assembler: 1, healthKit: 2), GoldenRevision("insulin-delivery-bolus", digest: "fCw3-HgNHCW_r1bQ8bY5WiGz52iekzNbJ0-AKZp59yc", assembler: 1, healthKit: 1), GoldenRevision("native-identifier-disclosure", digest: "d0cEPkdGfs7W8CYbUpS-GDKoc64jN21WjgkWSibIAAM", assembler: 1, healthKit: 2), - GoldenRevision("outlines", digest: "IO5I6QbUUxWkCk1WNeGrYpAP2KE-jxpeSajPwSH5dn0", assembler: 1, healthKit: 2), + GoldenRevision("outlines", digest: "SWyFVDm2r7z4Yqp6Y36Oub3aNtT6zO8emIKx-J5qmNs", assembler: 1, healthKit: 2), GoldenRevision("repository-ids-on-every-node", digest: "wnO8sPt82cYYd4m50n4tycbEXWdgvNRlKjQItQI6n4Y", assembler: 1, healthKit: 1), GoldenRevision("retraction-blood-pressure", digest: "x4muVgyjqh8AfgVGhaS55MeMVmxJ58UR0hsghhedkEA", assembler: 1, healthKit: 1), GoldenRevision("retraction-electrocardiogram", digest: "JJIp4J2S4Vr0CX-d1fi3IqAmyNzuzSz4fyrF-gbrkgM", assembler: 1, healthKit: 1), diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-default-apple-watch-heart-rate-without-unit-token.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-default-apple-watch-heart-rate-without-unit-token.json new file mode 100644 index 000000000..8f2922871 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/exporter-default-apple-watch-heart-rate-without-unit-token.json @@ -0,0 +1,350 @@ +{ + "entry" : [ + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:CJHBmXNaVbLnG4JvAxSfmTlcHtPNCHJMmdaBodV9X6I" + } + } + ], + "fullUrl" : "urn:uuid:cabb4303-bb19-5517-b216-fdd949d44b25", + "resource" : { + "_effectiveDateTime" : { + "extension" : [ + { + "url" : "http://hl7.org/fhir/StructureDefinition/timezone", + "valueCode" : "America/Los_Angeles" + } + ] + }, + "category" : [ + { + "coding" : [ + { + "code" : "vital-signs", + "display" : "Vital Signs", + "system" : "http://terminology.hl7.org/CodeSystem/observation-category" + } + ] + } + ], + "code" : { + "coding" : [ + { + "code" : "8867-4", + "display" : "Heart rate", + "system" : "http://loinc.org" + } + ] + }, + "effectiveDateTime" : "2026-08-17T15:30:00-07:00", + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type", + "valueCode" : "HKQuantityTypeIdentifierHeartRate" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:wNIJkcTb6o3RIct860I8RF0JgxtxxgBysgGUS_jXt0U" + }, + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1", + "type" : { + "coding" : [ + { + "code" : "source-output", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:CJHBmXNaVbLnG4JvAxSfmTlcHtPNCHJMmdaBodV9X6I" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate", + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation" + ] + }, + "resourceType" : "Observation", + "status" : "final", + "subject" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/patient", + "value" : "example" + }, + "type" : "Patient" + }, + "valueQuantity" : { + "code" : "/min", + "system" : "http://unitsofmeasure.org", + "unit" : "beats/minute", + "value" : 72 + } + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:rpOrjknDk_KBCvYM_cLFSodTfcpBVdINvEGQTkOuPmo" + } + } + ], + "fullUrl" : "urn:uuid:77d435c7-851f-5479-810e-0307f1dc0360", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test Host", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:rpOrjknDk_KBCvYM_cLFSodTfcpBVdINvEGQTkOuPmo" + } + ], + "manufacturer" : "Example Device Company", + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-host-device" + ] + }, + "modelNumber" : "Phone One", + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "os-version", + "display" : "Operating system version", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-application-version-type" + } + ] + }, + "value" : "20.1" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:dU14bqZUMgNm557Z24ivh0lJJ2Ekg8FoKIB6K1-C8xI" + } + } + ], + "fullUrl" : "urn:uuid:39d68db7-694a-5dee-9788-cf2b4b10035b", + "resource" : { + "deviceName" : [ + { + "name" : "Grove Test", + "type" : "user-friendly-name" + } + ], + "identifier" : [ + { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1", + "type" : { + "coding" : [ + { + "code" : "device-snapshot", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:dU14bqZUMgNm557Z24ivh0lJJ2Ekg8FoKIB6K1-C8xI" + }, + { + "system" : "https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id", + "type" : { + "coding" : [ + { + "code" : "apple-bundle-id", + "system" : "https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-identifier-type" + } + ] + }, + "value" : "org.grovealliance.test" + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-application-device" + ] + }, + "parent" : { + "reference" : "urn:uuid:77d435c7-851f-5479-810e-0307f1dc0360" + }, + "resourceType" : "Device", + "status" : "active", + "version" : [ + { + "type" : { + "coding" : [ + { + "code" : "531975", + "display" : "MDC_ID_PROD_SPEC_SW", + "system" : "urn:iso:std:iso:11073:10101" + } + ] + }, + "value" : "1.0" + } + ] + } + }, + { + "extension" : [ + { + "url" : "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-exchange-entry-node-key", + "valueIdentifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/entry-node", + "type" : { + "coding" : [ + { + "code" : "entry-node", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "n0:conversion-provenance:0:hkEAak9N9UWISSsswY7vgEMfiCyjfmcM3dlgoW2IfhE" + } + } + ], + "fullUrl" : "urn:uuid:9e36cd76-ea25-50f9-8900-e3aedd9208f7", + "resource" : { + "activity" : { + "coding" : [ + { + "code" : "transform", + "display" : "Transform/Translate Record Lifecycle Event", + "system" : "http://terminology.hl7.org/CodeSystem/iso-21089-lifecycle" + } + ] + }, + "agent" : [ + { + "type" : { + "coding" : [ + { + "code" : "assembler", + "display" : "Assembler", + "system" : "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who" : { + "reference" : "urn:uuid:39d68db7-694a-5dee-9788-cf2b4b10035b" + } + } + ], + "entity" : [ + { + "role" : "source", + "what" : { + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1", + "type" : { + "coding" : [ + { + "code" : "source-record", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "v0:test:1:wNIJkcTb6o3RIct860I8RF0JgxtxxgBysgGUS_jXt0U" + } + } + } + ], + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-conversion-provenance" + ] + }, + "occurredDateTime" : "2026-08-17T23:30:00Z", + "recorded" : "2026-08-17T23:30:00Z", + "resourceType" : "Provenance", + "target" : [ + { + "reference" : "urn:uuid:cabb4303-bb19-5517-b216-fdd949d44b25" + } + ] + } + } + ], + "identifier" : { + "system" : "https://grovealliance.org/fhir/testing/identifiers/healthkit/event", + "type" : { + "coding" : [ + { + "code" : "event", + "system" : "https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role" + } + ] + }, + "value" : "e0:1f5c58aa-6ec6-4e79-a682-829a9debd3f5:109" + }, + "meta" : { + "profile" : [ + "https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-exchange-bundle" + ] + }, + "resourceType" : "Bundle", + "timestamp" : "2026-08-17T23:30:00Z", + "type" : "collection" +} \ No newline at end of file diff --git a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json index cc9d21eb3..b60473ab6 100644 --- a/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json +++ b/Tests/GroveHealthKitFHIRTests/Resources/Goldens/outlines.json @@ -617,6 +617,55 @@ ] }, + "exporter-default-apple-watch-heart-rate-without-unit-token" : { + "entries" : [ + { + "extensions" : [ + "https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type" + ], + "fullUrl" : "urn:uuid:cabb4303-bb19-5517-b216-fdd949d44b25", + "identifiers" : [ + "source-record|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1|v0:test:1:wNIJkcTb6o3RIct860I8RF0JgxtxxgBysgGUS_jXt0U", + "source-output|https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1|v0:test:1:CJHBmXNaVbLnG4JvAxSfmTlcHtPNCHJMmdaBodV9X6I" + ], + "resourceType" : "Observation" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:77d435c7-851f-5479-810e-0307f1dc0360", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:rpOrjknDk_KBCvYM_cLFSodTfcpBVdINvEGQTkOuPmo" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:39d68db7-694a-5dee-9788-cf2b4b10035b", + "identifiers" : [ + "device-snapshot|https://grovealliance.org/fhir/testing/identifiers/healthkit/device-snapshot/test/1|v0:test:1:dU14bqZUMgNm557Z24ivh0lJJ2Ekg8FoKIB6K1-C8xI", + "apple-bundle-id|https://grovealliance.org/fhir/healthkit/NamingSystem/apple-bundle-id|org.grovealliance.test" + ], + "resourceType" : "Device" + }, + { + "extensions" : [ + + ], + "fullUrl" : "urn:uuid:9e36cd76-ea25-50f9-8900-e3aedd9208f7", + "identifiers" : [ + + ], + "resourceType" : "Provenance" + } + ], + "warnings" : [ + "mobile-omission.recording-device@Observation.device" + ] + }, "exporter-deployment-blood-pressure" : { "entries" : [ { From 726a2b7e8728e9c9888232298833676ec6eeb1c5 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 17:33:25 +0200 Subject: [PATCH 040/220] Discard the Receipt Stream in the Bulk Export Example Fix-round step G3 review, audit ledger section 3 finding 8 (docs that contradict the behaviour). G3 made FirebaseUploader's Output a HealthKitFHIRExporter.Receipt, so Example 1's `try session.start()` now resolves only to the @_disfavoredOverload start. That overload returns AsyncStream, so the line gave an unused-result warning, and the Void overload applies only when Processor.Output == Void. The example now writes `_ = try session.start()`. The prose says why discarding the stream is safe: publishOutput hands each receipt to didPersist whether or not anyone reads the stream (BulkExportSessionImpl.swift). Output unchanged (documentation only). Gates at this commit: GroveHealthKitFHIR macOS 294 total, 293 passed, 1 skipped (2a9f5ef1: 290 total, 289 passed, 1 skipped); swiftlint --strict on Sources/GroveFHIRContract, Sources/GroveHealthKitFHIR and Tests/GroveHealthKitFHIRTests: no findings; reuse lint: compliant. GroveFHIRContract sources are unchanged in this round, so the SensorKit, Questionnaire and iOS-15 contract gates do not apply. Size (A): code 11,186 (+1,481), public 1,006 (+133) Co-Authored-By: Claude Opus 5.5 --- .../GroveHealthKitBulkExport.docc/BulkHealthExporter.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/GroveHealthKitBulkExport/GroveHealthKitBulkExport.docc/BulkHealthExporter.md b/Sources/GroveHealthKitBulkExport/GroveHealthKitBulkExport.docc/BulkHealthExporter.md index d6e40a4ef..e2739db69 100644 --- a/Sources/GroveHealthKitBulkExport/GroveHealthKitBulkExport.docc/BulkHealthExporter.md +++ b/Sources/GroveHealthKitBulkExport/GroveHealthKitBulkExport.docc/BulkHealthExporter.md @@ -83,13 +83,13 @@ let session = try await bulkExporter.session( using: FirebaseUploader(participantID: participantID, exporter: exporter) ) -// start the session -try session.start() +// start the session; `didPersist` releases each receipt, so the stream of receipts goes unread +_ = try session.start() ``` This Bulk Export Session will, in the background, go through all historical Health data for the Active Energy, Heart Rate, and Step Count quantity types, fetch the data from HealthKit, and pass it to the Batch Processor, which will then upload it to Firebase. Firebase is only the destination chosen by this example; `GroveHealthKitFHIR` neither depends on Firebase nor reads from it. -In this example the `FirebaseUploader`'s outputs are receipts its own `didPersist` releases, so we simply call ``BulkExportSession/start(retryFailedBatches:concurrencyLevel:)`` and need nothing beyond that. +In this example the `FirebaseUploader`'s outputs are receipts, so ``BulkExportSession/start(retryFailedBatches:concurrencyLevel:)`` returns an `AsyncStream` of them. The session hands each receipt to the processor's `didPersist` once it has recorded the batch, whether or not anyone reads the stream, so the example discards the stream. From 99be924640ed906ab647e845f9f6d2089c07aa7a Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 18:16:31 +0200 Subject: [PATCH 041/220] Hand a Release Racing a Reuse Over to the Call That Still Holds It Fix-round step G1b, Codex fix-round review finding 4 (minor, confirmed by the repro run on 28f93119; final-spec 1.5.3 rule "the last live holder in this process removes the reservation if any holder released it", outcome row "anchor compare-exchange lost", G9d). HoldRegistry.end drops a handle's entry, and with it the released mark, when its last counted holder finishes. When another call had already reused that reservation (its reserve committed and was still noted as reserving, or it took its hold before the releaser's removal transaction opened), finish skipped the removal because the handle was held, and the reuser then acquired a fresh Hold(live: 1, released: false). If that call lapsed (a lost anchor compare-exchange, a throw, a cancellation), nothing removed the reservation although a holder had released it: an orphan. The release is now handed over inside the removing transaction, the point serialized against the competing reserve (a registry-only change in end cannot see the variant where the reuse holds before the transaction): - HoldRegistry.handOver(_:) replaces finish's isHeld check. When a live call holds the handle or a reserving transaction returned it, it marks the hold released (creating Hold(live: 0, released: true) for a call still reserving, which endReserving's live += 1 then takes over) and returns true, so finish keeps the reservation; otherwise it returns false and finish removes the reservation as before. Marking is idempotent, so a storage that runs the body again is unaffected. - endReserving drops a handed-over placeholder whose reserve never took its hold (a discarded attempt, or a reserve that threw), which then degrades to the documented "a failed release keeps the reservation". - Docs: the Storage.transaction doc and ExchangeLedgerStorage.md no longer say the process-memory notes end when the call returns (the handover outlives it; it is idempotent); finish's doc, its comment, the HoldRegistry doc and the article's holds section state the handover. isHeld stays for the test fixtures. Test (ExchangeEventHoldRaceTests, the repro's test kept as is): "G9d: a release racing a reuse keeps its mark; the reusing call's lapse removes the reservation", arguments [false, true] (reuse committed and still reserving; reuse fully holding before the removal transaction). Before this change both cases failed at the final expectation (the reservation stayed stored); after it both pass, as do the other hold, race and G5 property tests (narrowed GroveFHIR run over the five ledger suites: 39 tests, 36 passed; the 3 failures are the forget tests the next commit adds and fixes). Output unchanged: GroveFHIRContract's ledger only; no graph code touched. Co-Authored-By: Claude Opus 5.5 --- .../ExchangeEventSequencer+Holds.swift | 30 +++++++++++-- .../ExchangeEventSequencer.swift | 19 ++++---- .../ExchangeLedgerStorage.md | 4 +- .../ExchangeEventHoldRaceTests.swift | 45 +++++++++++++++++++ 4 files changed, 83 insertions(+), 15 deletions(-) diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer+Holds.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer+Holds.swift index 3d47a64d2..f73d4ef3e 100644 --- a/Sources/GroveFHIRContract/ExchangeEventSequencer+Holds.swift +++ b/Sources/GroveFHIRContract/ExchangeEventSequencer+Holds.swift @@ -15,10 +15,11 @@ import Foundation /// process finishes and any holder released it, so overlapping exports of one record never remove each /// other's reservation, and a call that throws leaves its reservations for the redelivery. A reserve notes the /// reservations its transaction returns from inside that transaction and turns them into holds in one step after -/// it, so a reservation it is about to hold is never seen unused in between. Handles include the producer -/// instance, which every ledger mints for itself, so they are unique across ledgers and the same through every -/// storage object or sequencer in front of one ledger; one registry serves every storage. Holds do not span -/// processes; the lock is never held across I/O. +/// it, so a reservation it is about to hold is never seen unused in between. A removal that finds such a holder +/// hands the release over to it, so the release mark survives until the last holder finishes. Handles include +/// the producer instance, which every ledger mints for itself, so they are unique across ledgers and the same +/// through every storage object or sequencer in front of one ledger; one registry serves every storage. Holds do +/// not span processes; the lock is never held across I/O. final class HoldRegistry: @unchecked Sendable { // `holds` and `reserving` are guarded by `lock`. /// The reservations one reserve call noted, so an attempt the storage runs again notes nothing twice. final class Notes: @unchecked Sendable { // `handles` is guarded by the registry's `lock`. @@ -63,6 +64,11 @@ final class HoldRegistry: @unchecked Sendable { // `holds` and `reserving` are g for handle in notes.handles { let remaining = (reserving[handle] ?? 1) - 1 reserving[handle] = remaining > 0 ? remaining : nil + // A release handed over to a reserve that then did not commit has no holder left to finish it; the + // reservation stays, as after a failed release. + if remaining <= 0, holds[handle]?.live == 0 { + holds[handle] = nil + } } notes.handles = [] } @@ -91,6 +97,22 @@ final class HoldRegistry: @unchecked Sendable { // `holds` and `reserving` are g return removable } + /// Whether a live call holds `handle` or a reserving transaction returned it to a call about to hold it; if so, + /// the release passes to that call, so the last holder to finish removes the reservation. Called inside the + /// removing transaction; marking again, when a storage runs that body again, changes nothing. + func handOver(_ handle: ExchangeEventReservation.Handle) -> Bool { + lock.lock() + defer { + lock.unlock() + } + guard holds[handle] != nil || reserving[handle] != nil else { + return false + } + // A call still reserving takes its hold on this entry, and with it the release mark. + holds[handle, default: Hold(live: 0, released: true)].released = true + return true + } + /// Whether a live call holds `handle`, or a reserving transaction returned it and its call is about to hold it. func isHeld(_ handle: ExchangeEventReservation.Handle) -> Bool { lock.lock() diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift index ef472fe35..daf61fbc5 100644 --- a/Sources/GroveFHIRContract/ExchangeEventSequencer.swift +++ b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift @@ -35,9 +35,9 @@ public final class ExchangeEventSequencer: Sendable { /// Runs `body` as one transaction and returns its result. /// /// The transaction is valid only inside `body`. Grove never calls `transaction` from inside `body`, - /// and its bodies have no effect outside the transaction other than process-memory notes that end - /// when the call returns, so a storage may discard an attempt and run `body` again. A `body` that - /// throws commits nothing. + /// and its bodies have no effect outside the transaction other than idempotent process-memory notes + /// about which calls hold a reservation, so a storage may discard an attempt and run `body` again. A + /// `body` that throws commits nothing. func transaction(_ body: (any Transaction) throws -> R) throws -> R } @@ -183,8 +183,9 @@ extension ExchangeEventSequencer { /// `released` says the caller's output is durably handed off. When the last live holder of a /// reservation in this process finishes and any holder released it, the reservation is removed, but /// only while the key still holds exactly that reservation and, checked inside the removing transaction, - /// no call in this process holds it or is about to. `keys` are forgotten whatever they hold, and only - /// when `released` is true. Opens one transaction when anything is to be removed, none otherwise. + /// no call in this process holds it or is about to; such a call takes the release over, so the last one + /// to finish removes it. `keys` are forgotten whatever they hold, and only when `released` is true. Opens + /// one transaction when anything is to be removed, none otherwise. package func finish( _ held: [ExchangeEventReservation.Handle], released: Bool, @@ -196,10 +197,10 @@ extension ExchangeEventSequencer { return } try storage.transaction { transaction in - // A reserve whose transaction returned the reservation noted it there, so it stays; a reserve whose - // transaction runs after this one no longer finds it, as a storage runs a process's transactions one at - // a time. - for handle in removable where !holds.isHeld(handle) { + // A reserve whose transaction returned the reservation noted it there, so it stays and that call takes the + // release over; a reserve whose transaction runs after this one no longer finds it, as a storage runs a + // process's transactions one at a time. + for handle in removable where !holds.handOver(handle) { let key = LedgerKey.event(handle.key) guard let value = try transaction.read(key) else { continue diff --git a/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md b/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md index 7f1806b1f..b1526afbf 100644 --- a/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md +++ b/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md @@ -45,7 +45,7 @@ What Grove promises a storage in return: - Keys are ASCII from `[A-Za-z0-9_/-]` and at most 64 bytes: `producer`, `event/` and `facts/`. - Values are UTF-8 JSON, typically under 1 KiB; accept values up to 1 MiB, as facts grow with the number of studies. -- Grove never nests transactions, never lets a transaction escape its body, and its bodies have no effect outside the transaction other than process-memory notes that end when the call returns, so a storage may discard an attempt and run the body again. +- Grove never nests transactions, never lets a transaction escape its body, and its bodies have no effect outside the transaction other than idempotent process-memory notes about which calls hold a reservation, so a storage may discard an attempt and run the body again. - `keys(prefixedBy:)` is called only by ``ExchangeEventSequencer/reset()`` and ``ExchangeEventSequencer/forgetReservations(madeBefore:)``. - One storage holds one ledger and nothing else. @@ -76,7 +76,7 @@ Both the cutoff and the stored instants are on the caller's clock, so choose one The entries hold no per-call state. Live calls are tracked in process memory: when the last call in the process that holds an event finishes and any of them released it, the event's reservation is removed, and otherwise it stays for the redelivery. -A reserve notes the reservations its transaction returns from inside that transaction until it holds them, and the removing transaction checks those notes and the holds, so a release never removes a reservation another call in the process holds or is about to hold, whichever storage object, value or sequencer either call goes through. +A reserve notes the reservations its transaction returns from inside that transaction until it holds them, and the removing transaction checks those notes and the holds, so a release never removes a reservation another call in the process holds or is about to hold, whichever storage object, value or sequencer either call goes through; that call takes the release over, and the last one to finish removes the reservation. This relies on the storage running one process's transactions one at a time, as every backend above in its primary form does with its lock or a transaction that takes the write lock when it begins. A storage whose serializable transactions overlap, such as one that validates optimistically, still never reuses a sequence, but there a release can remove a reservation that a concurrent call has just reused, and that call's redelivery then becomes a new event, a duplicate and never a reuse. A release only ever removes the exact reservation its call made, never a successor's or one from before a reset. diff --git a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldRaceTests.swift b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldRaceTests.swift index 038050b88..1363f4d66 100644 --- a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldRaceTests.swift +++ b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldRaceTests.swift @@ -268,4 +268,49 @@ struct ExchangeEventHoldRaceTests { #expect(redelivery.handle.instance == held.handle.instance) #expect(redelivery.handle.sequence > held.handle.sequence) } + + /// G9d under a race: the last holder releases while another call reuses the reservation, either committed but not yet + /// holding it (`reuseHoldsBeforeRemoval` false) or fully holding it before the release's transaction opens (true). + @Test("G9d: a release racing a reuse keeps its mark; the reusing call's lapse removes the reservation", arguments: [false, true]) + func releaseRacingAReuseThenLapse(reuseHoldsBeforeRemoval: Bool) throws { + let storage = GateStorage() + let sequencer = Fixtures.sequencer(storage) + let request = Fixtures.request("race") + let facts = try Fixtures.facts() + let first = try sequencer.reserve([request], at: Fixtures.instant, facts: facts) + let reused: [ExchangeEventRequest: ExchangeEventReservation] + if reuseHoldsBeforeRemoval { + // The last holder ended its hold and waits to open its removal transaction; another call reuses it now. + let finished = DispatchSemaphore(value: 0) + storage.gate() + Thread { + try? sequencer.finish(first.values.map(\.handle), released: true, forgetting: []) + finished.signal() + }.start() + storage.entered.wait() + reused = try sequencer.reserve([request], at: Fixtures.instant, facts: facts) + storage.proceed.signal() + finished.wait() + } else { + // Another call's reuse committed and is still noted as reserving when the last holder releases. + let box = ReservedBox() + let reserved = DispatchSemaphore(value: 0) + storage.gate(.afterCommit) + Thread { + box.reserved = (try? sequencer.reserve([request], at: Fixtures.instant, facts: facts)) ?? [:] + reserved.signal() + }.start() + storage.entered.wait() + try sequencer.finish(first.values.map(\.handle), released: true, forgetting: []) + storage.proceed.signal() + reserved.wait() + reused = box.reserved + } + #expect(reused == first, "the second call reused the reservation") + #expect(try Fixtures.stored(LedgerKey.event(request.key), in: storage.base) != nil, "the second call still holds it") + // The reusing call is dropped unreleased, as the loser of an anchor compare-exchange is; it is the last holder. + try sequencer.finish(reused.values.map(\.handle), released: false, forgetting: []) + #expect(!Fixtures.isHeld(first[request]?.handle, by: sequencer)) + #expect(try Fixtures.stored(LedgerKey.event(request.key), in: storage.base) == nil, "a holder released it; the last finisher removes it") + } } From 9ec585271c61ce8cef3063e580e56089cb4d652d Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 18:18:49 +0200 Subject: [PATCH 042/220] Forget Only What a Retraction Receipt's Own Ledger Generation Reserved Fix-round step G1b, Codex fix-round review finding 3 (major, confirmed by the repro run on 28f93119; final-spec 1.5.3 and 1.5.5, G10, G11). finish removed every forgotten key "unconditionally" (1.5.3). A retraction receipt's forget list is bare active keys, so a receipt from before reset() removed a reservation minted after it, against reset's promise "a receipt from before the reset releases nothing" (1.5.5, G10); the live export's redelivery then minted a new event instead of the exact retry. The repro's variants fail the same way: a post-reset export whose receipt lapsed, and, without any reset, a live export of the record while its retraction is released. A forget is now owned, like a removal: - finish forgets a key only when its stored reservation carries a producer instance of the receipt's own handles. reset() mints a new instance, so a pre-reset receipt matches nothing; a caller that holds nothing owns nothing to forget and opens no transaction. - A forgotten reservation a live call holds (or is about to) goes through HoldRegistry.handOver, the previous commit's mechanism: it stays, and the last holder to finish removes it, even by a lapse. The repro's isHeld-only guard would leave it behind as an orphan instead. - Both loops read the stored reservation through one helper. Consequence (accepted in the repro): a retraction with nothing to retract reserves nothing and therefore forgets nothing; an active reservation of an output-less type then stays until reset() or forgetReservations, at a disk cost only, as the spec's other MHC orphans. Docs: finish, retract(_:at:receive:), Receipt and ExchangeLedgerStorage.md (cost and holds sections) state the owned forget and that a receipt with nothing reserved runs no transaction. Tests: - New HealthKitFHIRExporterForgetTests (GroveHealthKitFHIRTests): the repro's reset sequence with the post-reset export live or lapsed (arguments), and the live-export variant, whose lapsing last holder removes what the retraction forgot. Before this change all three cases failed (the reservation was gone, the redelivery a new event). - ExchangeEventHoldTests: forgettingRemovesUnconditionally pinned the unconditional rule and is replaced by three discriminating tests: forgetting is owned and only on release (and a caller holding nothing forgets nothing with no transaction), a forget from before a reset removes nothing, and a forgotten reservation a live call holds passes to it. All three failed before this change. - HealthKitFHIRExporterCallTests.nothingToRetractStillForgets becomes nothingToRetractForgetsNothing: (0, 0) on release instead of (1, 1). Narrowed runs: GroveFHIR ledger suites 41/41, GroveHealthKitFHIR forget/call/ledger suites 18/18. Output unchanged: ledger bookkeeping only; no graph code touched. Co-Authored-By: Claude Opus 5.5 --- .../ExchangeEventSequencer.swift | 35 +++++++--- .../ExchangeLedgerStorage.md | 5 +- .../HealthKitFHIRExporter+Results.swift | 2 +- .../HealthKitFHIRExporter+Retraction.swift | 6 +- .../ExchangeEventHoldTests.swift | 51 ++++++++++++-- .../HealthKitFHIRExporterCallTests.swift | 6 +- .../HealthKitFHIRExporterForgetTests.swift | 70 +++++++++++++++++++ 7 files changed, 150 insertions(+), 25 deletions(-) create mode 100644 Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterForgetTests.swift diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift index daf61fbc5..2e3ba4062 100644 --- a/Sources/GroveFHIRContract/ExchangeEventSequencer.swift +++ b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift @@ -184,15 +184,19 @@ extension ExchangeEventSequencer { /// reservation in this process finishes and any holder released it, the reservation is removed, but /// only while the key still holds exactly that reservation and, checked inside the removing transaction, /// no call in this process holds it or is about to; such a call takes the release over, so the last one - /// to finish removes it. `keys` are forgotten whatever they hold, and only when `released` is true. Opens - /// one transaction when anything is to be removed, none otherwise. + /// to finish removes it. Only when `released` is true are `keys` forgotten: each key's reservation, whatever + /// event it holds, is removed the same way when a producer instance of `held` made it, so a caller from + /// before a reset, or one that holds nothing, forgets nothing. Opens one transaction when anything is to be + /// removed, none otherwise. package func finish( _ held: [ExchangeEventReservation.Handle], released: Bool, forgetting keys: [ExchangeEventKey] ) throws { let removable = holds.end(held, released: released) - let forgotten = released ? keys : [] + // A reset mints a new producer instance, so nothing reserved after it carries one of these. + let instances = Set(held.map(\.instance)) + let forgotten = released && !instances.isEmpty ? keys : [] guard !removable.isEmpty || !forgotten.isEmpty else { return } @@ -201,18 +205,27 @@ extension ExchangeEventSequencer { // release over; a reserve whose transaction runs after this one no longer finds it, as a storage runs a // process's transactions one at a time. for handle in removable where !holds.handOver(handle) { - let key = LedgerKey.event(handle.key) - guard let value = try transaction.read(key) else { - continue - } - let stored = try EventEntry(decoding: value, key: key) - if stored.instance == handle.instance && stored.sequence == handle.sequence { - try transaction.remove(key) + if try Self.reservation(of: handle.key, in: transaction) == handle { + try transaction.remove(LedgerKey.event(handle.key)) } } for key in forgotten { - try transaction.remove(LedgerKey.event(key)) + if let stored = try Self.reservation(of: key, in: transaction), instances.contains(stored.instance), !holds.handOver(stored) { + try transaction.remove(LedgerKey.event(key)) + } } } } } + + +extension ExchangeEventSequencer { + /// The reservation `key` holds in `transaction`, if any. + private static func reservation(of key: ExchangeEventKey, in transaction: any Transaction) throws -> ExchangeEventReservation.Handle? { + let entryKey = LedgerKey.event(key) + return try transaction.read(entryKey).map { value in + let stored = try EventEntry(decoding: value, key: entryKey) + return ExchangeEventReservation.Handle(key: key, instance: stored.instance, sequence: stored.sequence) + } + } +} diff --git a/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md b/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md index b1526afbf..74718c5c7 100644 --- a/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md +++ b/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md @@ -64,7 +64,7 @@ What Grove promises a storage in return: An export or retraction is one transaction that touches only the entries of its own event keys, the `producer` entry and each distinct facts entry once; a reservation that is reused writes nothing. Releasing a receipt is at most one more transaction. An export's receipt runs none when it reserved nothing, or when another call in the process still holds its events. -A retraction's receipt runs one whenever it names a deletion, even of a type with nothing to retract, because it also forgets each deleted record's active reservation. +A retraction's receipt runs one whenever it reserved a retraction event, because it also forgets each deleted record's active reservation; one that reserved nothing runs none and forgets nothing. Backends that store entries individually (in memory, Core Data, SQL) therefore cost what a call touches, whatever the ledger's size. The single-file and keychain backends rewrite the whole map on every transaction and suit small ledgers, or ledgers you prune. @@ -80,7 +80,8 @@ A reserve notes the reservations its transaction returns from inside that transa This relies on the storage running one process's transactions one at a time, as every backend above in its primary form does with its lock or a transaction that takes the write lock when it begins. A storage whose serializable transactions overlap, such as one that validates optimistically, still never reuses a sequence, but there a release can remove a reservation that a concurrent call has just reused, and that call's redelivery then becomes a new event, a duplicate and never a reuse. A release only ever removes the exact reservation its call made, never a successor's or one from before a reset. -The one exception is a retraction's receipt: on release it forgets each deleted record's active reservation, whatever that reservation is, because no export will release it once the record is gone. +The one exception is a retraction's receipt: on release it also forgets each deleted record's active reservation, whatever event that reservation holds, because no export will release it once the record is gone. +It forgets only a reservation made under the producer instance of its own retraction events, never one from after a reset, and a reservation a live call still holds passes to that call, whose last finish removes it. Holds do not span processes; when two live processes share one storage, a release in one can remove a reservation the other still holds, and the other's redelivery then becomes a new event, a duplicate and never a reuse. ## Topics diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift index 0b03666b2..7b0cb5778 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Results.swift @@ -100,7 +100,7 @@ extension HealthKitFHIRExporter { /// same events, byte for byte. Releasing is idempotent, also across copies of this reference, and makes /// one ledger transaction at most. An export's receipt makes none when nothing was reserved, or while /// another call in this process still holds the same events. A retraction's receipt makes one whenever it - /// names a deletion, as it also forgets each deleted record's active reservation. + /// reserved a retraction, as it also forgets each deleted record's active reservation, and none otherwise. /// /// A receipt dropped unreleased (the call threw, or its commit action was discarded) leaves its /// reservations for the redelivery. When another call in this process released the same event, the last diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift index e0bcb0b1d..1780bb389 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift @@ -21,8 +21,10 @@ extension HealthKitFHIRExporter { /// /// Every retraction event is reserved in one ledger transaction. Two deletions of one record with /// different bounds are two events. Releasing the receipt also forgets each deleted record's active - /// reservation, which no export will release once the record is gone. The call ends early for the - /// same reasons as ``export(_:at:receive:)``: an unstatable `instant`, a `LedgerError` (recovered by + /// reservation, which no export will release once the record is gone: one the same ledger generation + /// made, never one from after a `reset()`, and one a live export still holds only once that export + /// finishes. A call with nothing to retract forgets nothing. The call ends early for the same reasons as + /// ``export(_:at:receive:)``: an unstatable `instant`, a `LedgerError` (recovered by /// `ExchangeEventSequencer.reset()`), and errors of the ledger's storage or of `receive`. public func retract( _ deletions: some Collection, diff --git a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldTests.swift b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldTests.swift index 5e0d121d3..b169c988e 100644 --- a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldTests.swift +++ b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldTests.swift @@ -159,15 +159,54 @@ struct ExchangeEventHoldTests { #expect(storage.takeCounts().transactions == 0, "a lapse with no released holder touches nothing") } - @Test("Forgetting removes a key whatever it holds, and only on release") - func forgettingRemovesUnconditionally() throws { - let storage = ExchangeEventSequencer.InMemoryStorage() + @Test("Forgetting removes a key's reservation of the caller's own instance, and only on release") + func forgettingIsOwnedAndOnlyOnRelease() throws { + let storage = CountingStorage() let sequencer = Fixtures.sequencer(storage) let active = Fixtures.request("a") - _ = try sequencer.reserve([active], at: Fixtures.instant, facts: Fixtures.facts()) - try sequencer.finish([], released: false, forgetting: [active.key]) - #expect(try Self.isReserved(active, in: storage)) + let retraction = Fixtures.request("a", kind: .retraction) + let lapsed = try sequencer.reserve([active], at: Fixtures.instant, facts: Fixtures.facts()) + try sequencer.finish(lapsed.values.map(\.handle), released: false, forgetting: []) + let dropped = try sequencer.reserve([retraction], at: Fixtures.instant, facts: Fixtures.facts()) + try sequencer.finish(dropped.values.map(\.handle), released: false, forgetting: [active.key]) + #expect(try Self.isReserved(active, in: storage), "a lapse forgets nothing") + _ = storage.takeCounts() try sequencer.finish([], released: true, forgetting: [active.key]) + #expect(storage.takeCounts().transactions == 0, "a caller that holds nothing owns nothing to forget") + #expect(try Self.isReserved(active, in: storage)) + let released = try sequencer.reserve([retraction], at: Fixtures.instant, facts: Fixtures.facts()) + try sequencer.finish(released.values.map(\.handle), released: true, forgetting: [active.key]) #expect(try !Self.isReserved(active, in: storage)) } + + @Test("G10: forgetting from before a reset removes nothing minted after it") + func forgettingFromBeforeAResetRemovesNothing() throws { + let storage = ExchangeEventSequencer.InMemoryStorage() + let sequencer = Fixtures.sequencer(storage) + let active = Fixtures.request("a") + let retraction = try sequencer.reserve([Fixtures.request("a", kind: .retraction)], at: Fixtures.instant, facts: Fixtures.facts()) + try sequencer.reset() + let after = try sequencer.reserve([active], at: Fixtures.instant, facts: Fixtures.facts()) + try sequencer.finish(after.values.map(\.handle), released: false, forgetting: []) + try sequencer.finish(retraction.values.map(\.handle), released: true, forgetting: [active.key]) + #expect(try Self.isReserved(active, in: storage), "a receipt from before the reset releases nothing") + #expect(try sequencer.reserve([active], at: Fixtures.instant, facts: Fixtures.facts()) == after) + } + + @Test("G9: forgetting a reservation a live call holds leaves it to that call, whose finish removes it") + func forgettingAHeldReservationHandsItOver() throws { + let storage = ExchangeEventSequencer.InMemoryStorage() + let sequencer = Fixtures.sequencer(storage) + let active = Fixtures.request("a") + let live = try sequencer.reserve([active], at: Fixtures.instant, facts: Fixtures.facts()) + let retraction = try sequencer.reserve([Fixtures.request("a", kind: .retraction)], at: Fixtures.instant, facts: Fixtures.facts()) + try sequencer.finish(retraction.values.map(\.handle), released: true, forgetting: [active.key]) + #expect(try Self.isReserved(active, in: storage), "the live call still holds it") + #expect(try sequencer.reserve([active], at: Fixtures.instant, facts: Fixtures.facts()) == live, "its redelivery is an exact retry") + try sequencer.finish(live.values.map(\.handle), released: false, forgetting: []) + #expect(try Self.isReserved(active, in: storage), "the redelivery still holds it") + try sequencer.finish(live.values.map(\.handle), released: false, forgetting: []) + #expect(try !Self.isReserved(active, in: storage), "the last holder to finish removes what the retraction forgot") + #expect(!Fixtures.isHeld(live[active]?.handle, by: sequencer)) + } } diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterCallTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterCallTests.swift index 231a4f027..9e8c95766 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterCallTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterCallTests.swift @@ -75,8 +75,8 @@ struct HealthKitFHIRExporterCallTests { #expect(storage.take().transactions == 1) } - @Test("A retraction with nothing to retract reserves nothing; its release still forgets the deleted record's active reservation") - func nothingToRetractStillForgets() throws { + @Test("A retraction with nothing to retract reserves nothing, so its release owns nothing to forget and touches no ledger") + func nothingToRetractForgetsNothing() throws { let storage = LedgerCountingStorage() let exporter = try Fixtures.exporter(sequencer: ExchangeEventSequencer(storage: storage)) let deletion = HealthKitFHIRExporter.Deletion( @@ -92,7 +92,7 @@ struct HealthKitFHIRExporterCallTests { } #expect(storage.take().transactions == 0) receipt.release() - #expect(storage.take() == (transactions: 1, writes: 1)) + #expect(storage.take() == (transactions: 0, writes: 0)) } @Test("A released receipt dropped while another call holds the same event leaves the event to that call") diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterForgetTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterForgetTests.swift new file mode 100644 index 000000000..32d7f15a4 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterForgetTests.swift @@ -0,0 +1,70 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +@testable import GroveFHIRContract +@testable import GroveHealthKitFHIR +import Testing + + +/// A retraction receipt forgets the deleted record's active reservation only when its own ledger generation made it and +/// no live call still holds it: a receipt from before `reset()` releases nothing, and a live export keeps its event. +@Suite +struct HealthKitFHIRExporterForgetTests { + private typealias Fixtures = ExporterFixtures + + @Test("G10/G11: a retraction receipt from before a reset forgets no reservation minted after it", arguments: [false, true]) + func preResetRetractionReceiptKeepsAPostResetReservation(exportLapses: Bool) throws { + let storage = LedgerCountingStorage() + let exporter = try Fixtures.exporter(sequencer: ExchangeEventSequencer(storage: storage)) + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0xC0)) + let key = try #require(ExchangeEventKey.active(sample)) + // A retraction of the same record, still unreleased when the ledger is reset. + let retraction = try Fixtures.retract(exporter, [Fixtures.deletion(0xC0)]) + try exporter.producer.sequencer.reset() + // An export after the reset, whose receipt stays live or lapses: either way its redelivery is an exact retry. + var first: [HealthKitFHIRExporter.Export] = [] + var receipt: HealthKitFHIRExporter.Receipt? = try exporter.export([sample], at: GoldenFixtures.conversionInstant) { first.append($0) } + if exportLapses { + receipt = nil + } + #expect(first[0].sequence == "1") + retraction.receipt.release() + #expect(try storage.holdsReservation(for: key), "a receipt from before the reset releases nothing") + let (again, againReceipt) = try Fixtures.collect(exporter, samples: [sample]) + #expect(again[0].event == first[0].event, "a redelivery before release reuses the event") + #expect(again[0].graph?.json == first[0].graph?.json, "a redelivery before release is byte-identical") + receipt?.release() + againReceipt.release() + } + + @Test("G9/G11: a released retraction leaves a live export's reservation to it; that call's last finish removes it") + func releasedRetractionLeavesALiveExportItsEvent() throws { + let storage = LedgerCountingStorage() + let exporter = try Fixtures.exporter(sequencer: ExchangeEventSequencer(storage: storage)) + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0xC1)) + let key = try #require(ExchangeEventKey.active(sample)) + var first: [HealthKitFHIRExporter.Export] = [] + var receipt: HealthKitFHIRExporter.Receipt? = try exporter.export([sample], at: GoldenFixtures.conversionInstant) { first.append($0) } + try Fixtures.retract(exporter, [Fixtures.deletion(0xC1)]).receipt.release() + #expect(try storage.holdsReservation(for: key), "the live export still holds its event") + // A redelivery whose receipt lapses at once, as a call that threw does. + let again = try Fixtures.collect(exporter, samples: [sample]).exports + #expect(again[0].event == first[0].event, "the live export's redelivery is an exact retry") + #expect(again[0].graph?.json == first[0].graph?.json) + #expect(try storage.holdsReservation(for: key), "the first call still holds it") + // No holder released it, but the retraction forgot it: the last holder to finish removes it, even by a lapse. + #expect(receipt != nil) + receipt = nil + #expect(try !storage.holdsReservation(for: key), "the last holder to finish removes what the retraction forgot") + } +} + +#endif From d3d6a1bf8d330da8072723ebf6a70afd7374cfa1 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 18:21:09 +0200 Subject: [PATCH 043/220] Keep One Fingerprint per Event Key and Call So Exact Retries Stay Exact Fix-round step G1b, Codex fix-round review finding 2 (major, confirmed by the repro run on 28f93119; final-spec 1.5.1 "same key, different fingerprints in one call", 2.4, 4.3, G4). One key reserved under two fingerprints in one call minted two sequences and kept only the later one in the key's single slot, so an exact retry of that call before release minted both again (1, 2, then 3, 4) and wrote 3 entries: against "an exact redelivery before release reproduces the same events byte for byte" and the IG's event.retry rule. The documented retract API reaches it (two deletions of one record with different bounds); the export path reaches it when one call names a record twice with different content. The fix stays in the adapter; the sequencer and the ledger layout are unchanged (requestsAreDistinctByFingerprint still pins 1.5.1): - Retractions: a deletion's bounds (clamped deletedAfter and detectedAt, in milliseconds) move from the fingerprint's record parts into the retraction key's revision (ExchangeEventKey.retraction, parts joined by "|", which decimal milliseconds never contain). Each occurrence keeps its own reservation, so both events are reused on retry; identical deletions still collapse into one, and changed bounds are still a new event (G4 unchanged). Trade-off, documented on retract: a deletion reported again with other bounds no longer replaces the earlier bounds' unreleased reservation; that one stays until its own receipt is released (disk only). - Exports: each key keeps the first request in input order. A plan with a request that lost (a record, or an ECG's symptom, named earlier in the call with other content) is refused with the new HealthKitConversionError.conflictingDuplicate (mobile-input.unclassified at HKSample), checked right after the source type, as the error type's refusal order now states. The rule is deterministic, so a retry refuses identically and reuses every reservation. Only contradictory input reaches it (HealthKit records are immutable per UUID, and MHC's staging tables are unique per type and UUID); a refusal, not a thrown call, so a batch never wedges on it. - The sequencer's reserve doc states that callers request one fingerprint per key and call for exact retries. Tests (new HealthKitFHIRExporterBatchRetryTests, from the repro): - An exact retry of [0xC0 with bounds, 0xC0 without, control 0xC1] through the public retract API reuses all three events, byte for byte, with 0 writes. Before: retry sequences 5, 4 for 3, 2 and 3 writes. - An exact retry of [ECG 0xC2 with [one], ECG 0xC2 with [two, one]]: the later input is refused as conflictingDuplicate (diagnostic pinned), and the retry reuses every event with 0 writes. Before: the ECG took sequences 6, 5 for 3, 2. The repro's sequencer-level test is not kept, as it pins the replace semantics this fix deliberately leaves alone. Narrowed run of the exporter suites (batch, ledger, record, exporter, call, forget, fingerprint): 44/44. Output unchanged: the retraction key is ledger-only, and the refusal adds no graph; goldens untouched. Co-Authored-By: Claude Opus 5.5 --- .../ExchangeEventSequencer.swift | 4 +- .../HealthKitConversionError.swift | 12 ++- .../HealthKitFHIRExporter+Retraction.swift | 25 +++--- .../HealthKitFHIRExporter.swift | 14 +++- ...HealthKitFHIRExporterBatchRetryTests.swift | 79 +++++++++++++++++++ 5 files changed, 118 insertions(+), 16 deletions(-) create mode 100644 Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterBatchRetryTests.swift diff --git a/Sources/GroveFHIRContract/ExchangeEventSequencer.swift b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift index 2e3ba4062..0a5c51a74 100644 --- a/Sources/GroveFHIRContract/ExchangeEventSequencer.swift +++ b/Sources/GroveFHIRContract/ExchangeEventSequencer.swift @@ -144,7 +144,9 @@ extension ExchangeEventSequencer { /// unchanged: the same producer instance, sequence, instant and facts, and writes nothing. Any other /// request takes the next sequence at `instant` (millisecond precision) under `facts`, replacing what /// the key held. New sequences follow the requests' sorted order; a counter that would overflow mints - /// a new producer instance. A sequence is never handed out twice. Each returned reservation is held + /// a new producer instance. A sequence is never handed out twice. A key requested under two fingerprints + /// in one call takes two sequences and keeps the later, so a retry of that call mints both again: request + /// one fingerprint per key and call for exact retries. Each returned reservation is held /// for the caller until ``finish(_:released:forgetting:)``. Exporters reach it through /// `ExchangeProducer.reserve(_:at:)`, which passes the facts the producer prepared once. /// diff --git a/Sources/GroveHealthKitFHIR/HealthKitConversionError.swift b/Sources/GroveHealthKitFHIR/HealthKitConversionError.swift index 4b1c477ac..83d0862ea 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConversionError.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConversionError.swift @@ -128,8 +128,9 @@ public struct HealthKitDependencyFailure: Error, Equatable, Sendable { /// A fail-closed refusal from the HealthKit conversion facade; every case reports one registry code. /// /// A record with several faults is refused for the first in this order, whatever the options: its source type, then -/// its content (values, units, effective times), then what it states about its origin (its recording device, its -/// writer, its sync identifier and version). A content fault thus reads the same under every writer policy. +/// whether the export call named it before with other content, then its content (values, units, effective times), +/// then what it states about its origin (its recording device, its writer, its sync identifier and version). A content +/// fault thus reads the same under every writer policy. public enum HealthKitConversionError: Error, Equatable, Sendable { /// The identifier is not in the adapter inventory at all. case unregisteredSourceType(String) @@ -149,6 +150,10 @@ public enum HealthKitConversionError: Error, Equatable, Sendable { case repositoryIDWithoutNode(ExchangeGraphNode) /// A disclosed native identifier system reuses one of the deployment's Grove identity systems. case reservedIdentifierSystem + /// The export call named the record, or an ECG's symptom, earlier with other content: other companion data, or + /// other answers from a policy closure. The first input keeps the record's event; each later one that differs is + /// refused, so an exact retry of the call reproduces every event. + case conflictingDuplicate case exchangeIdentity(ExchangeIdentityError) case opaqueIdentity(OpaqueIdentityError) case exchangeGraph(ExchangeGraphError) @@ -179,7 +184,7 @@ public enum HealthKitConversionError: Error, Equatable, Sendable { case .ecgEvidence: .healthkitInputEcgEvidence case .clinicalRecord(let failure): failure.rule case .sourceApplicationInvalid: .healthkitInputSourceApplicationInvalid - case .repositoryIDWithoutNode, .reservedIdentifierSystem, .exchangeIdentity, .opaqueIdentity, .dependency: + case .repositoryIDWithoutNode, .reservedIdentifierSystem, .conflictingDuplicate, .exchangeIdentity, .opaqueIdentity, .dependency: .mobileInputUnclassified case .exchangeGraph(let error): ExchangeGraphRule(rawValue: error.diagnostic.code) ?? .mobileExchangeUnclassified } @@ -195,6 +200,7 @@ public enum HealthKitConversionError: Error, Equatable, Sendable { case .clinicalRecord: "HKClinicalRecord.fhirResource" case .sourceApplicationInvalid: "HKSourceRevision.source.bundleIdentifier" case .repositoryIDWithoutNode, .reservedIdentifierSystem: "HealthKitConversionContext" + case .conflictingDuplicate: "HKSample" case .exchangeIdentity, .opaqueIdentity, .exchangeGraph, .dependency: "Bundle" } } diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift index 1780bb389..8bfbe6f02 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Retraction.swift @@ -20,19 +20,21 @@ extension HealthKitFHIRExporter { /// Targets are recomputed from the catalog, so nothing from the original export needs to be kept. /// /// Every retraction event is reserved in one ledger transaction. Two deletions of one record with - /// different bounds are two events. Releasing the receipt also forgets each deleted record's active - /// reservation, which no export will release once the record is gone: one the same ledger generation - /// made, never one from after a `reset()`, and one a live export still holds only once that export - /// finishes. A call with nothing to retract forgets nothing. The call ends early for the same reasons as - /// ``export(_:at:receive:)``: an unstatable `instant`, a `LedgerError` (recovered by - /// `ExchangeEventSequencer.reset()`), and errors of the ledger's storage or of `receive`. + /// different bounds are two events, each under its own key, so an exact retry of the call reproduces + /// both; a deletion reported again with other bounds is another event, and the reservation of the + /// earlier bounds stays until its own receipt is released. Releasing the receipt also forgets each + /// deleted record's active reservation, which no export will release once the record is gone: one the + /// same ledger generation made, never one from after a `reset()`, and one a live export still holds + /// only once that export finishes. A call with nothing to retract forgets nothing. The call ends early + /// for the same reasons as ``export(_:at:receive:)``: an unstatable `instant`, a `LedgerError` + /// (recovered by `ExchangeEventSequencer.reset()`), and errors of the ledger's storage or of `receive`. public func retract( _ deletions: some Collection, at instant: Date = .now, receive: (Export) throws -> Void ) throws -> Receipt { let requests = deletions.map { deletion in - isRetractable(deletion) ? context.request(for: .retraction(deletion), recordParts: deletion.occurrenceParts) : nil + isRetractable(deletion) ? context.request(for: .retraction(deletion)) : nil } let unique = Set(requests.compactMap(\.self)) let reserved = unique.isEmpty ? [:] : try producer.reserve(unique, at: instant) @@ -100,7 +102,7 @@ extension HealthKitFHIRExporter.Deletion { deletedAfter.flatMap { $0 <= detectedAt ? $0 : nil } } - /// What the retraction key does not version but the graph states: the bounds, in milliseconds. + /// The bounds the retraction states, in milliseconds; the lower one is empty when unknown. var occurrenceParts: [String] { [ clampedDeletedAfter.map { String(ExchangeInstant.millisecondsSinceEpoch($0)) } ?? "", @@ -112,12 +114,15 @@ extension HealthKitFHIRExporter.Deletion { @available(iOS 18, macOS 15, watchOS 11, *) extension ExchangeEventKey { - /// The retraction-event key of a deletion: the source type and UUID under the retraction kind. + /// The retraction-event key of a deletion: the source type and UUID under the retraction kind, with the bounds + /// the retraction states as its revision, so each reported occurrence keeps a reservation of its own. static func retraction(_ deletion: HealthKitFHIRExporter.Deletion) -> ExchangeEventKey { ExchangeEventKey( kind: .retraction, adapterID: HealthKitConverter.adapterID, - sourceRecord: "\(deletion.sourceType.rawValue)|\(deletion.uuid.uuidString.lowercased())" + sourceRecord: "\(deletion.sourceType.rawValue)|\(deletion.uuid.uuidString.lowercased())", + // Decimal milliseconds or empty, so the separator is unambiguous. + revision: deletion.occurrenceParts.joined(separator: "|") ) } } diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift index f8e518573..6efd2a30c 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift @@ -71,7 +71,9 @@ public final class HealthKitFHIRExporter: Sendable { /// Converts samples in input order, calling `receive` once per produced graph or refusal as soon as /// it is ready. /// - /// A record that cannot be converted is refused in place; only these end the call: + /// A record that cannot be converted is refused in place, and so is a record the call names again with + /// other content (``HealthKitConversionError/conflictingDuplicate``): the first input of a record keeps + /// its event, so an exact retry of the call reproduces every event. Only these end the call: /// - an `instant` no FHIR instant can state (before year 1 or after year 9999) throws /// `ExchangeIdentityError.invalidInstant` before the ledger is touched; /// - the producer's ledger throws `ExchangeEventSequencer.LedgerError` when a stored entry is corrupt or @@ -98,7 +100,10 @@ public final class HealthKitFHIRExporter: Sendable { /// One reserve transaction for every event the inputs need, then each input's delivery in order. func export(inputs: [Input], at instant: Date, receive: (Export) throws -> Void) throws -> Receipt { let plans = inputs.map { Plan($0, context: context) } - let requests = Set(plans.flatMap(\.requests)) + // One fingerprint per key and call, the first in input order: a key reserved under two would keep only the + // later, and a retry of the call would mint both again. + let firstPerKey = Dictionary(plans.flatMap(\.requests).map { ($0.key, $0) }) { first, _ in first } + let requests = Set(firstPerKey.values) // Nothing reserved means the ledger is never touched; refusals alone need no event. let reserved = requests.isEmpty ? [:] : try producer.reserve(requests, at: instant) // Created before any delivery: when a delivery throws, the receipt is dropped and its holds lapse. @@ -185,6 +190,11 @@ extension HealthKitFHIRExporter { try receive(Export(source: plan.source, outcome: .refused(refusal), warnings: [])) return } + guard plan.requests.allSatisfy({ reserved[$0] != nil }) else { + // An earlier input of this call named one of its records with other content and holds that key's event. + try receive(Export(source: plan.source, outcome: .refused(.conflictingDuplicate), warnings: [])) + return + } // A refusal keeps its reservations held: they are released with the receipt, never mid-call, so a // standalone export of the same record in this call keeps its event. let set: HealthKitConversionSet? diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterBatchRetryTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterBatchRetryTests.swift new file mode 100644 index 000000000..0b4a2c76f --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterBatchRetryTests.swift @@ -0,0 +1,79 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +@testable import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit +import Testing + + +/// An exact retry, before release, of a call that names one record twice with different content. +@Suite +struct HealthKitFHIRExporterBatchRetryTests { + private typealias Fixtures = ExporterFixtures + + @Test("An exact retry of two deletions of one record with different bounds in one call redelivers both events") + func retryOfTwoBoundsInOneCallIsExact() throws { + let storage = LedgerCountingStorage() + let exporter = try Fixtures.exporter(sequencer: ExchangeEventSequencer(storage: storage)) + let deletions = [ + Fixtures.deletion(0xC0, deletedAfter: GoldenFixtures.sampleStart), + Fixtures.deletion(0xC0, deletedAfter: nil), + // A control: another record under one fingerprint. + Fixtures.deletion(0xC1, deletedAfter: GoldenFixtures.sampleStart) + ] + let first = try Fixtures.retract(exporter, deletions) + _ = storage.take() + let retry = try Fixtures.retract(exporter, deletions) + let writes = storage.take().writes + try #require(first.exports.count == 3 && retry.exports.count == 3) + #expect(first.exports[0].event != first.exports[1].event, "two bounds are two events") + #expect(retry.exports[2].sequence == first.exports[2].sequence, "control: a single-fingerprint key is reused") + #expect(retry.exports[0..<2].map(\.sequence) == first.exports[0..<2].map(\.sequence)) + #expect(retry.exports.map(\.graph?.json) == first.exports.map(\.graph?.json)) + #expect(writes == 0, "an exact retry writes nothing") + first.receipt.release() + retry.receipt.release() + } + + @Test("A call naming one ECG under two symptom sets refuses the later one, and its exact retry reuses every event") + func retryOfTwoSymptomSetsInOneCallIsExact() throws { + let storage = LedgerCountingStorage() + let exporter = try Fixtures.exporter(sequencer: ExchangeEventSequencer(storage: storage)) + let one = try GoldenCase.symptom(uuid: GoldenFixtures.uuid(0xC3)) + let two = try GoldenCase.symptom(uuid: GoldenFixtures.uuid(0xC4), type: .fatigue) + let inputs = [ + try Fixtures.electrocardiogram(uuid: 0xC2, symptoms: [one]), + try Fixtures.electrocardiogram(uuid: 0xC2, symptoms: [two, one]) + ] + let first = try Fixtures.collect(exporter, inputs) + _ = storage.take() + let retry = try Fixtures.collect(exporter, inputs) + let writes = storage.take().writes + let ecg = try #require(inputs.first?.sample.uuid) + // The first input's ECG and its symptom, then the later input refused: one event per key and call. + try #require(first.exports.map(\.source.uuid) == [ecg, one.uuid, ecg]) + #expect(first.exports[0].graph != nil && first.exports[1].graph != nil) + guard case .refused(let reason) = first.exports[2].outcome else { + Issue.record("expected the later input to be refused, got \(first.exports[2].outcome)") + return + } + #expect(reason == .conflictingDuplicate) + #expect(reason.diagnostic == ExchangeGraphRule.mobileInputUnclassified.diagnostic(at: "HKSample")) + #expect(retry.exports.map(\.event) == first.exports.map(\.event)) + #expect(retry.exports.map(\.graph?.json) == first.exports.map(\.graph?.json)) + #expect(writes == 0, "an exact retry writes nothing") + first.receipt.release() + retry.receipt.release() + } +} + +#endif From 76e4f37a4f4e43ba5624a988768f4b75addfd837 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 18:22:02 +0200 Subject: [PATCH 044/220] Replace the One-Case Writer Draft Enum With a Struct Fix-round step G1b, from the Codex fix-round review's simplification list (ExchangeGraphDraft.swift:188-192). With the .device writer gone (final-spec 3.1), ExchangeWriterDraft was an enum with one case, .application(ApplicationDevice, host:, statesVersion:): the draft's optional already says whether a writer is stated, so the enum only made the assembler pattern-match a value it could read. It is now a package struct with the three fields; the assembler's writerSnapshots reads them after `guard let writer`, and SourceFacts builds the struct. The explicit package init is the struct's only extra code (the adapter is another module). Output unchanged, verified by GoldenGraphTests, HealthKitFHIRExporterWriterTests and HealthKitApplicationIdentityTests (narrowed GroveHealthKitFHIR run, 15/15; goldens byte-equal) and by the full gate run at the end of this step. Co-Authored-By: Claude Opus 5.5 --- .../ExchangeGraphAssembler+Devices.swift | 8 ++++---- .../GroveFHIRContract/ExchangeGraphDraft.swift | 18 +++++++++++++----- .../HealthKitAssembly+SourceFacts.swift | 4 ++-- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/Sources/GroveFHIRContract/ExchangeGraphAssembler+Devices.swift b/Sources/GroveFHIRContract/ExchangeGraphAssembler+Devices.swift index ff0158a8c..588eafc01 100644 --- a/Sources/GroveFHIRContract/ExchangeGraphAssembler+Devices.swift +++ b/Sources/GroveFHIRContract/ExchangeGraphAssembler+Devices.swift @@ -148,17 +148,17 @@ extension ExchangeGraphAssembler { repositoryIDs: [ExchangeGraphNode: RepositoryID], converter: ConverterSnapshots ) throws -> WriterSnapshots? { - guard case let .application(application, hostDevice, statesVersion) = writer else { + guard let writer else { return nil } - let host = try hostSnapshot(hostDevice, event: event, repositoryID: repositoryIDs[.writerHost]) + let host = try hostSnapshot(writer.host, event: event, repositoryID: repositoryIDs[.writerHost]) var snapshot = try applicationSnapshot( - application, + writer.application, event: event, parentURL: try host.identity.fullURLString, repositoryID: repositoryIDs[.writer] ) - if !statesVersion { + if !writer.statesVersion { var resource = snapshot.resource resource.version = nil snapshot = IdentifiedDevice(resource: resource, identity: snapshot.identity) diff --git a/Sources/GroveFHIRContract/ExchangeGraphDraft.swift b/Sources/GroveFHIRContract/ExchangeGraphDraft.swift index 67fde0366..d44fb2bb7 100644 --- a/Sources/GroveFHIRContract/ExchangeGraphDraft.swift +++ b/Sources/GroveFHIRContract/ExchangeGraphDraft.swift @@ -184,11 +184,19 @@ package struct ExchangeRecordingDeviceDraft: Sendable { } -/// Who wrote the record into the source store, as the Provenance author; a draft without one names no author. -package enum ExchangeWriterDraft: Sendable { - /// An application and the host it ran on, stated as snapshots of their own; `statesVersion` is - /// false when the source named no version, so the Device carries none. - case application(ApplicationDevice, host: HostDevice, statesVersion: Bool) +/// The application that wrote the record into the source store, and the host it ran on, stated as snapshots of their +/// own and as the Provenance author; a draft without one names no author. +package struct ExchangeWriterDraft: Sendable { + package let application: ApplicationDevice + package let host: HostDevice + /// False when the source named no version, so the application Device carries none. + package let statesVersion: Bool + + package init(application: ApplicationDevice, host: HostDevice, statesVersion: Bool) { + self.application = application + self.host = host + self.statesVersion = statesVersion + } } diff --git a/Sources/GroveHealthKitFHIR/HealthKitAssembly+SourceFacts.swift b/Sources/GroveHealthKitFHIR/HealthKitAssembly+SourceFacts.swift index 0df3bf648..f8caeed39 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitAssembly+SourceFacts.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitAssembly+SourceFacts.swift @@ -111,8 +111,8 @@ extension HealthKitAssembly.SourceFacts { } let version = revision.version?.nonBlank do { - return .application( - try ApplicationDevice(name: name, bundleIdentifier: bundleIdentifier, version: version ?? "unknown"), + return ExchangeWriterDraft( + application: try ApplicationDevice(name: name, bundleIdentifier: bundleIdentifier, version: version ?? "unknown"), host: try HostDevice( operatingSystemVersion: operatingSystemVersion(revision.operatingSystemVersion), modelNumber: revision.productType?.nonBlank From 9f5e122b961bf6ec1c65738874e8c95ed2e30bfc Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 18:24:15 +0200 Subject: [PATCH 045/220] Key ECG Symptom Requests by UUID Throughout the Assembly Fix-round step G1b, from the Codex fix-round review's simplification list (HealthKitAssembly+Records.swift:22-26, 82-94). HealthKitAssembly.SymptomRequests carried two shapes through the assembly (positional for the deprecated context API, keyed by UUID for the exporter) only to normalize them inside symptomConversions. The assembly now takes the keyed shape alone: - HealthKitConverter.symptomRequests(_:for:) converts the context API's positional symptom contexts at its entry points (the deprecated convert(_:context:symptomContexts:) and the tests' convertECG seam), with the same count check and first-context-wins keying as before. - The record-based HealthKitAssembly.convertECG is gone; its evidence step is HealthKitECGEvidence.init(_ record:), which the deprecated API and the exporter's records path call before the evidence-based convertECG, the only ECG conversion left. The refusal order is unchanged: the context validations, then the ECG evidence, then the symptom-context count, then the symptoms' validation. No content builder (ECGCore, the validator, the time kernels) is touched. Test (HealthKitECGEvidenceValidatorTests): the context API refuses a symptom-context count other than the symptoms' before it validates the symptoms (symptoms present although the evidence says none still report symptomContextCountMismatch). It guards the moved check; it passes before and after this change, as the order is preserved. Narrowed GroveHealthKitFHIR run (ECG validator, goldens, converter, exporter ledger, record and batch suites): all passed. Output unchanged (goldens byte-equal). Co-Authored-By: Claude Opus 5.5 --- .../HealthKitAssembly+Records.swift | 55 ++++++------------- .../HealthKitConverter+ECG.swift | 19 ++++++- .../HealthKitFHIRExporter.swift | 13 +++-- .../HealthKitConverter+TestSeams.swift | 2 +- .../HealthKitECGEvidenceValidatorTests.swift | 15 +++++ 5 files changed, 58 insertions(+), 46 deletions(-) diff --git a/Sources/GroveHealthKitFHIR/HealthKitAssembly+Records.swift b/Sources/GroveHealthKitFHIR/HealthKitAssembly+Records.swift index b49d628e6..b547d5366 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitAssembly+Records.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitAssembly+Records.swift @@ -17,35 +17,26 @@ import ModelsR4 // MARK: - Electrocardiogram @available(iOS 18, macOS 15, watchOS 11, *) -extension HealthKitAssembly { - /// The requests of an ECG's correlated symptoms. - enum SymptomRequests { - /// One request per symptom, in the record's order: the context API's shape. - case positional([Request]) - /// Each symptom's request under its sample's UUID: the exporter's shape, paired by event key. - case keyed([UUID: Request]) - } - - /// Converts an already-fetched ECG and every correlated symptom as independently exchangeable - /// source events, each symptom under its own request. - func convertECG(_ record: HealthKitECGRecord, request: Request, symptomRequests: SymptomRequests) throws -> HealthKitConversionSet { +extension HealthKitECGEvidence { + /// The validated evidence of an already-fetched ECG and its voltages. + init(_ record: HealthKitECGRecord) throws { let source = try HealthKitConverter.ecgSourceEvidence(record.electrocardiogram) - return try convertECG( - record.electrocardiogram, - evidence: HealthKitECGEvidence(source: source, waveform: try HealthKitConverter.validatedWaveform(for: record, source: source)), - symptoms: record.correlatedSymptoms, - request: request, - symptomRequests: symptomRequests - ) + self.init(source: source, waveform: try HealthKitConverter.validatedWaveform(for: record, source: source)) } +} + - /// `ecg` supplies only the envelope's identity, device and source facts; the evidence is given. +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitAssembly { + /// Converts an ECG and every correlated symptom as independently exchangeable source events, each symptom under + /// the request keyed by its sample's UUID. `ecg` supplies only the envelope's identity, device and source facts; + /// the evidence is given. func convertECG( _ ecg: HKSample, evidence: HealthKitECGEvidence, symptoms: [HKCategorySample], request: Request, - symptomRequests: SymptomRequests + symptomRequests: [UUID: Request] ) throws -> HealthKitConversionSet { let companions = try symptomConversions(symptoms, source: evidence.source, symptomRequests: symptomRequests) let input = HealthKitECGObservationInput( @@ -77,28 +68,14 @@ extension HealthKitAssembly { private func symptomConversions( _ correlatedSymptoms: [HKCategorySample], source: HealthKitECGSourceEvidence, - symptomRequests: SymptomRequests + symptomRequests: [UUID: Request] ) throws -> [HealthKitConversion] { - let requestsBySample: [UUID: Request] - switch symptomRequests { - case .positional(let requests): - guard requests.count == correlatedSymptoms.count else { - throw HealthKitConversionError.ecgEvidence(.symptomContextCountMismatch( - symptoms: correlatedSymptoms.count, - contexts: requests.count - )) - } - requestsBySample = Dictionary(zip(correlatedSymptoms.map(\.uuid), requests), uniquingKeysWith: { first, _ in first }) - case .keyed(let requests): - requestsBySample = requests - } // Validation comes first, so an unsupported or duplicated symptom is refused as such. let symptoms = try HealthKitConverter.validatedSymptomSamples(correlatedSymptoms, status: source.symptomsStatus) return try symptoms.map { symptom in - guard let request = requestsBySample[symptom.uuid] else { - // The positional shape keys every symptom; the keyed shape keys every symptom of a registered type, - // and validation admits only symptom types that are registered. - preconditionFailure("Every validated symptom has a request in both shapes.") + guard let request = symptomRequests[symptom.uuid] else { + // Both callers key every symptom of a registered type, and validation admits only registered types. + preconditionFailure("Every validated symptom has a request.") } return try convert(symptom, request: request).primary } diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+ECG.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+ECG.swift index a657e86f5..f36ba72e5 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+ECG.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter+ECG.swift @@ -35,10 +35,13 @@ extension HealthKitConverter { for symptomContext in symptomContexts { try Self.validateSymptomConversionContext(symptomContext, expectedContext: context) } + let evidence = try HealthKitECGEvidence(record) return try HealthKitAssembly(context: context.event).convertECG( - record, + record.electrocardiogram, + evidence: evidence, + symptoms: record.correlatedSymptoms, request: .init(context: context), - symptomRequests: .positional(symptomContexts.map { .init(context: $0) }) + symptomRequests: try Self.symptomRequests(symptomContexts, for: record.correlatedSymptoms) ) } catch { throw HealthKitConversionError(conversionFailure: error, source: .electrocardiogram) @@ -49,6 +52,18 @@ extension HealthKitConverter { @available(iOS 18, macOS 15, watchOS 11, *) extension HealthKitConverter { + /// The context API's one context per symptom, in the record's order, as the assembly's requests keyed by each + /// symptom's UUID; a repeated symptom keeps its first context, and the symptom validation refuses it. + static func symptomRequests( + _ contexts: [HealthKitConversionContext], + for symptoms: [HKCategorySample] + ) throws -> [UUID: HealthKitAssembly.Request] { + guard contexts.count == symptoms.count else { + throw HealthKitConversionError.ecgEvidence(.symptomContextCountMismatch(symptoms: symptoms.count, contexts: contexts.count)) + } + return Dictionary(zip(symptoms.map(\.uuid), contexts.map(HealthKitAssembly.Request.init(context:)))) { first, _ in first } + } + /// A companion belongs to the same subject, repository scope and identity scope as the ECG. static func validateSymptomConversionContext( _ symptomContext: HealthKitConversionContext, diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift index 6efd2a30c..736891e3c 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift @@ -238,8 +238,13 @@ extension HealthKitFHIRExporter { case .record(.sample(let sample)): return try assembly.convert(sample, request: request) case let .record(.electrocardiogram(ecg, voltages, symptoms)): - let ecgRecord = HealthKitECGRecord(electrocardiogram: ecg, voltageMeasurements: voltages, correlatedSymptoms: symptoms) - return try assembly.convertECG(ecgRecord, request: request, symptomRequests: symptomRequests(plan, reserved: reserved)) + return try assembly.convertECG( + ecg, + evidence: HealthKitECGEvidence(HealthKitECGRecord(electrocardiogram: ecg, voltageMeasurements: voltages)), + symptoms: symptoms, + request: request, + symptomRequests: symptomRequests(plan, reserved: reserved) + ) case let .record(.heartbeatSeries(series, beats)): return try assembly.convertHeartbeatSeries(HealthKitHeartbeatSeriesRecord(series: series, heartbeats: beats), request: request) case let .record(.workoutRoute(route, locations)): @@ -259,7 +264,7 @@ extension HealthKitFHIRExporter { private func symptomRequests( _ plan: Plan, reserved: [ExchangeEventRequest: ExchangeEventReservation] - ) throws -> HealthKitAssembly.SymptomRequests { + ) throws -> [UUID: HealthKitAssembly.Request] { var requests: [UUID: HealthKitAssembly.Request] = [:] for (symptom, planned) in zip(plan.input.symptoms, plan.symptoms) { guard let planned, requests[symptom.uuid] == nil else { @@ -267,7 +272,7 @@ extension HealthKitFHIRExporter { } requests[symptom.uuid] = try request(for: symptom, reservation: reservation(for: planned, in: reserved)) } - return .keyed(requests) + return requests } /// An omission a policy chose is never reported. diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitConverter+TestSeams.swift b/Tests/GroveHealthKitFHIRTests/HealthKitConverter+TestSeams.swift index a278f6787..0281ac9b9 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitConverter+TestSeams.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitConverter+TestSeams.swift @@ -55,7 +55,7 @@ extension HealthKitConverter { evidence: evidence, symptoms: symptoms, request: .init(context: context), - symptomRequests: .positional(symptomContexts.map { .init(context: $0) }) + symptomRequests: try symptomRequests(symptomContexts, for: symptoms) ) } diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitECGEvidenceValidatorTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitECGEvidenceValidatorTests.swift index 8dd7f8c97..ca36fcdd4 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitECGEvidenceValidatorTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitECGEvidenceValidatorTests.swift @@ -378,6 +378,21 @@ struct HealthKitECGEvidenceValidatorTests { #expect(set.warnings == symptomWarnings) } + @Test("The context API refuses a symptom-context count other than the symptoms' before it validates the symptoms") + func symptomContextCountIsCheckedBeforeTheSymptoms() throws { + // Symptoms the evidence says are absent: the count mismatch is still the fault reported. + let (ecg, evidence) = try GoldenCase.electrocardiogramEvidence(uuid: 0x60, symptomsPresent: false) + #expect(throws: HealthKitConversionError.ecgEvidence(.symptomContextCountMismatch(symptoms: 1, contexts: 0))) { + try HealthKitConverter.convertECG( + ecg, + evidence: evidence, + symptoms: [symptom(.dizziness)], + context: HealthKitConversionContext(), + symptomContexts: [] + ) + } + } + private func symptom(_ type: HKCategoryTypeIdentifier) -> HKCategorySample { HKCategorySample( type: HKCategoryType(type), From c16211e78edbb43284cb9421bd4ced95b6f6b690 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 18:33:19 +0200 Subject: [PATCH 046/220] Fingerprint Companion Data and the Policies' Answers per Record Fix-round step G1b, Codex fix-round review finding 1 (major, confirmed by the repro run on 28f93119; final-spec 0 "record-level companion data ... so an identifier is never reused for different content", 2.4 recordParts, 9 residual "closures are not fingerprinted", G3, G4). The IG's event.retry rule: "Any source revision or content change receives a new sequence". The record parts held only an ECG's sorted symptom UUIDs, so a reserved event was reused for other bytes when, before release, a redelivery carried other heartbeat beats, route locations or ECG voltages, or when a .custom recording-device resolver or a .classify writer closure answered otherwise (both entered the fingerprint by their presence only). Companion data: each kind enters the record's parts as a tag and the SHA-256 (base64url) of exactly what the assembly serializes: - "beats": HealthKitConverter.beatIntervalPayload(seriesStart:heartbeats:); - "locations": HealthKitConverter.locationTrackPayload(_:); - "voltages": the validated waveform's first and last offsets, period and data, length-framed (what SampledData and the effective period state), for the public .electrocardiogram record and the evidence seam alike; - the ECG's symptom set is now tagged too ("symptoms", count, sorted UUIDs), so every group fixes how many parts follow it. A payload that throws enters as "unserializable": the assembly throws the same, so the record is refused and no graph carries the part. Beats and locations are serialized twice (plan and assembly; small CSVs). An ECG record's voltages are validated once: planning turns a record whose evidence validates into the evidence seam's input (Input.validated), so the assembly reuses that evidence; one that does not validate stays as given and is refused on delivery for the same reason as before. Closure policies (the orchestrator's decision, public API unchanged): the writer and recording-device policies are resolved once per sample, before the reservation (HealthKitFHIRExporter.ResolvedPolicies, held per event by Plan.Event), and the record's parts state the answers: the writer classification, and "none" or the resolved unit's token, name, manufacturer and model, everything of the recording Device the graph states beside the immutable HKDevice. The graph is built from those same answers (ResolvedRecordingDevice passes the resolved unit to the assembly), so what is fingerprinted is exactly what is emitted, and a closure is consulted once per record and call. Every policy resolves this way, not only the closures, so there is one path; for .omit, .applications and .localIdentifier the answers are functions of the call parts and the immutable sample, so they only restate them. The private OmittingRecordingDeviceResolver and RecordingDevicePolicy.resolver give way to RecordingDevicePolicy.recordingDevice(for:). Each ECG symptom's event resolves its own sample's policies. Docs: ExportContext, the WriterPolicy fingerprint parts, WriterPolicy .classify and RecordingDevicePolicy.custom (no longer "must be pure ... can restate a reserved event's writer"; now consulted once per record, its answer fingerprinted), and ExchangeLedgerStorage.md's list of what takes a new sequence. Spec 2.4's record-parts list and its 9 closure residual are superseded as described (the spec file itself is the orchestrator's). Tests: - New ExporterCompanionFingerprintTests (the repro's suite, kept as is, plus three): a changed beat, location or voltage, a custom resolver naming another unit, or the same unit under another name, and a .classify closure answering otherwise each take a new sequence under a reserved record while an exact redelivery stays byte-identical. Before this change all six failed (the event was reused for other bytes). A seventh guards the resolve-once property: a resolver answering unit-a first and unit-b afterwards, then a fixed unit-a resolver over the same ledger, must reuse the event with the same bytes. It passed before (the old code also consulted the resolver once) and fails under the mutation that consults the policy again for the graph. - HealthKitFHIRExporterFingerprintTests: G3's stored-fingerprint check compares with the planned request (call and record parts), and a new known answer pins a record's parts (writer application, the watch's unit token, name, manufacturer, model) and its fingerprint 4ViljxvhC5STfq5O5V-a8ML-YL42xAqmwAycm0BO414, as the call parts' known answer does, so the derivation changes only on purpose. - HealthKitFHIRExporterLedgerTests E1 reads the plan's events. Output unchanged: no output revision bump, no golden change (equal inputs give equal bytes; only ledger fingerprints change, so pending reservations take a new sequence once, which the IG allows). Verified by the full GroveHealthKitFHIR macOS run, goldens byte-equal. Gates for this step (at this tree, which is the step's final tree): - GroveHealthKitFHIR macOS (Scripts/run-package-tests.sh): Passed, 307 total, 306 passed, 1 skipped (the throughput benchmark), 0 failed. - GroveFHIR macOS (the ledger suites): Passed, 106/106. - GroveSensorKitFHIR macOS: Passed, 85/85. GroveQuestionnaire macOS: Passed, 260/260 (GroveFHIRContract changed in this step). - GROVE_LOWERED_DEPLOYMENT_TARGETS=1 xcrun swift build --target GroveFHIRContract: Build complete (no Mutex, no Regex added). - swiftlint lint --strict --quiet (GroveFHIRContract, GroveHealthKitFHIR, GroveHealthKitFHIRTests, and Tests/GroveFHIRTests/ExchangeLedger): no findings. - reuse lint: compliant (2892/2892). Size (A): code 11,289 (+1,584), public 1,008 (+135) (vs baseline Grove 9b086e60; vs this step's base 726a2b7e: code +103, public +2, the new HealthKitConversionError.conflictingDuplicate case, which the tool counts twice; its unique public list grows by one. Per commit: handover +14, owned forget +7, one fingerprint per key +8 / +2, writer draft struct +7, keyed symptom requests -3, this commit +70. Level B: code 21,351 (+1,584), public 1,911 (+135).) Co-Authored-By: Claude Opus 5.5 --- .../ExchangeLedgerStorage.md | 2 +- .../HealthKitFHIRExporter+Fingerprint.swift | 96 +++++++- .../HealthKitFHIRExporter+Options.swift | 30 ++- .../HealthKitFHIRExporter.swift | 79 ++++--- .../ExporterCompanionFingerprintTests.swift | 207 ++++++++++++++++++ ...ealthKitFHIRExporterFingerprintTests.swift | 23 +- .../HealthKitFHIRExporterLedgerTests.swift | 4 +- 7 files changed, 391 insertions(+), 50 deletions(-) create mode 100644 Tests/GroveHealthKitFHIRTests/ExporterCompanionFingerprintTests.swift diff --git a/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md b/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md index 74718c5c7..11498ade3 100644 --- a/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md +++ b/Sources/GroveFHIRContract/GroveFHIRContract.docc/ExchangeLedgerStorage.md @@ -18,7 +18,7 @@ Every exchange event is immutable: a retry resends the same bytes under the same ``ExchangeEventSequencer`` keeps that promise on the device. It numbers the events of one installation, and until an exporter's receipt is released it keeps, per event key, the producer instance, the sequence, the instant and the facts (application, host, studies) the event states. An exact redelivery after a crash, an app update or an operating-system update rebuilds byte-identical output from those frozen facts. -When anything that shapes the output but is not frozen has changed (the converter's output revision, the identity scope, the subject, the repository scope or an option), the event takes a new sequence instead. +When anything that shapes the output but is not frozen has changed (the converter's output revision, the identity scope, the subject, the repository scope, an option, what a policy answered for the record, or record content its key does not version, such as an ECG's voltages), the event takes a new sequence instead. Grove owns the ledger's logic and its entries. Your application supplies only the durable storage, through ``ExchangeEventSequencer/Storage``: a transactional map from string keys to byte values. diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift index 970292167..edace5140 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift @@ -40,10 +40,11 @@ extension HealthKitFHIRExporter { /// the identity scope, the subject, the repository scope and every option. /// /// A request's fingerprint is the SHA-256, base64url without padding, of the length-framed call parts - /// followed by the record's own parts. A stored reservation is reused only under an equal fingerprint, so - /// a Grove update that changes output, any option change, or another participant over the same ledger - /// never reuses an event identifier for other bytes. A ``WriterPolicy/classify(_:)`` closure and a custom - /// ``RecordingDevicePolicy`` resolver enter by their presence only; their behaviour is not fingerprinted. + /// followed by the record's own parts: what the writer and recording-device policies answered for its + /// sample (`ResolvedPolicies`) and its companion data (`Input.companionParts`). A stored reservation is + /// reused only under an equal fingerprint, so a Grove update that changes output, any option change, a + /// policy closure that answers otherwise, other companion data, or another participant over the same + /// ledger never reuses an event identifier for other bytes. struct ExportContext: Sendable { /// The length-framed parts every request of this exporter starts with, in order. private let framedCallParts: Data @@ -99,6 +100,81 @@ extension HealthKitFHIRExporter.Options { } +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitFHIRExporter { + /// What the writer and recording-device policies answer for one sample, resolved once, before its event is + /// reserved: the event's fingerprint covers these answers and its graph states them, so a + /// ``WriterPolicy/classify(_:)`` closure or a custom ``RecordingDevicePolicy`` resolver that answers otherwise + /// for a reserved record takes a new sequence instead of restating the reserved event. + struct ResolvedPolicies: ExchangeContextFingerprinted { + let writer: HealthKitWriter + /// `nil` when the sample names no `HKDevice` or the policy declines it. + let recordingDevice: RecordingDevice? + + /// The writer tag, then the recording device's: `none`, or `unit` and every value of the device the graph + /// states, its token (which keys the Device's identities) and its optional name, manufacturer and model. + var fingerprintParts: [String] { + let device = recordingDevice.map { device in + ["unit", device.stableUnitToken] + optionalParts(device.name) + optionalParts(device.manufacturer) + optionalParts(device.modelNumber) + } + return ["writer"] + writer.fingerprintParts + ["recordingDevice"] + (device ?? ["none"]) + } + + init(_ sample: HKSample, options: Options) { + self.writer = options.writer.classification(of: sample.sourceRevision.source) + self.recordingDevice = sample.device.flatMap(options.recordingDevice.recordingDevice(for:)) + } + } +} + + +@available(iOS 18, macOS 15, watchOS 11, *) +extension HealthKitFHIRExporter.Input { + /// The record content its event key does not version but its graph serializes: an ECG's symptom set (its + /// Observation references their outputs) and voltages, a heartbeat series' beats and a route's locations. Each + /// kind enters as a tag and the digest of exactly what the assembly serializes from it. + var companionParts: [String] { + switch self { + case .record(.sample): + return [] + case let .electrocardiogramEvidence(_, evidence, symptoms): + return Self.symptomParts(symptoms) + ["voltages", Self.digest { try evidence.waveform.serialized() }] + case let .record(.electrocardiogram(ecg, voltages, symptoms)): + // A planned input still carries raw voltages only when they do not validate, and the record is refused. + let record = HealthKitECGRecord(electrocardiogram: ecg, voltageMeasurements: voltages) + return Self.symptomParts(symptoms) + ["voltages", Self.digest { try HealthKitECGEvidence(record).waveform.serialized() }] + case let .record(.heartbeatSeries(series, beats)): + return ["beats", Self.digest { try HealthKitConverter.beatIntervalPayload(seriesStart: series.startDate, heartbeats: beats) }] + case let .record(.workoutRoute(_, locations)): + return ["locations", Self.digest { try HealthKitConverter.locationTrackPayload(locations) }] + } + } + + /// The symptom count, then their lowercase UUIDs, sorted. + private static func symptomParts(_ symptoms: [HKCategorySample]) -> [String] { + ["symptoms", String(symptoms.count)] + symptoms.map { $0.uuid.uuidString.lowercased() }.sorted() + } + + /// The SHA-256, base64url without padding, of `serialized`, or `unserializable` when it throws: the assembly + /// throws the same, so the record is refused and no graph ever carries the part. + private static func digest(_ serialized: () throws -> Data) -> String { + guard let bytes = try? serialized() else { + return "unserializable" + } + return Data(SHA256.hash(data: bytes)).base64URLEncodedStringWithoutPadding + } +} + + +extension HealthKitECGValidatedWaveform { + /// What the ECG Observation's SampledData and effective period state from the voltages, length-framed: the + /// first and last offsets, the period and the data. + func serialized() throws -> Data { + try LengthFramedUTF8.encode([firstOffsetSeconds.description, lastOffsetSeconds.description, periodMilliseconds.description, data]) + } +} + + /// An optional value's parts: a presence tag, then the value. private func optionalParts(_ value: String?) -> [String] { value.map { ["some", $0] } ?? ["none"] @@ -128,7 +204,7 @@ extension HealthKitFHIRExporter.WriterPolicy: ExchangeContextFingerprinted { /// byte order, so sets of the same strings, byte for byte, fingerprint equally whatever their insertion order. /// `Set` equality is canonical equivalence, so two sets that spell a member in different Unicode normalization /// forms compare equal yet fingerprint apart: a new sequence, never a reused one. A closure enters by its - /// presence only; how it classifies is the caller's to keep stable. + /// presence here; what it answers for each record enters that record's parts (`ResolvedPolicies`). var fingerprintParts: [String] { switch self { case .omit: @@ -143,6 +219,16 @@ extension HealthKitFHIRExporter.WriterPolicy: ExchangeContextFingerprinted { } +extension HealthKitWriter: ExchangeContextFingerprinted { + var fingerprintParts: [String] { + switch self { + case .application: ["application"] + case .omit: ["omit"] + } + } +} + + @available(iOS 18, macOS 15, watchOS 11, *) extension HealthKitFHIRExporter.RecordingDevicePolicy: ExchangeContextFingerprinted { var fingerprintParts: [String] { diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift index 2780df546..66ba06678 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift @@ -12,11 +12,14 @@ public import GroveFHIRContract public import HealthKit -/// The resolver behind ``HealthKitFHIRExporter/RecordingDevicePolicy/omit``. +/// The unit a ``HealthKitFHIRExporter/RecordingDevicePolicy`` resolved for one sample before its event was reserved, so +/// the graph states the device the event's fingerprint covers without consulting the policy again. @available(iOS 18, macOS 15, watchOS 11, *) -private struct OmittingRecordingDeviceResolver: RecordingDeviceResolver { - func recordingDevice(for device: HKDevice) -> RecordingDevice? { - nil +struct ResolvedRecordingDevice: RecordingDeviceResolver { + let device: RecordingDevice? + + func recordingDevice(for _: HKDevice) -> RecordingDevice? { + device } } @@ -74,9 +77,9 @@ extension HealthKitFHIRExporter { /// identifier states none either, and one whose bundle identifier is not a valid Apple bundle identifier /// is refused with ``HealthKitConversionError/sourceApplicationInvalid``. case applications(Set) - /// The caller classifies each source. The closure must be a pure function of the source and stable - /// across application versions: the context fingerprint records only that a closure classifies, so - /// a closure whose answers change can restate a reserved event's writer differently on redelivery. + /// The caller classifies each source. The closure is consulted once per record and call, before the + /// record's event is reserved, and the event's fingerprint covers its answer: an answer that changes for a + /// reserved record takes a new sequence rather than restating that event's writer. case classify(@Sendable (HKSource) -> HealthKitWriter) /// The classification of one source under this policy. @@ -99,17 +102,20 @@ extension HealthKitFHIRExporter { case localIdentifier /// Never emit a recording Device from `HKDevice`. case omit - /// The deployment's own resolver. + /// The deployment's own resolver. It is consulted once per record and call, before the record's event is + /// reserved, and the event's fingerprint covers the device it names: a resolver whose answer changes for a + /// reserved record takes a new sequence rather than restating that event's recording Device. case custom(any RecordingDeviceResolver) - var resolver: any RecordingDeviceResolver { + /// The unit this policy resolves `device` to. + func recordingDevice(for device: HKDevice) -> RecordingDevice? { switch self { case .localIdentifier: - HealthKitLocalIdentifierResolver() + HealthKitLocalIdentifierResolver().recordingDevice(for: device) case .omit: - OmittingRecordingDeviceResolver() + nil case .custom(let resolver): - resolver + resolver.recordingDevice(for: device) } } } diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift index 736891e3c..06d36eb35 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter.swift @@ -99,7 +99,11 @@ public final class HealthKitFHIRExporter: Sendable { /// One reserve transaction for every event the inputs need, then each input's delivery in order. func export(inputs: [Input], at instant: Date, receive: (Export) throws -> Void) throws -> Receipt { - let plans = inputs.map { Plan($0, context: context) } + let plans = inputs.map { input in + autoreleasepool { + Plan(input, exporter: self) + } + } // One fingerprint per key and call, the first in input order: a key reserved under two would keep only the // later, and a retry of the call would mint both again. let firstPerKey = Dictionary(plans.flatMap(\.requests).map { ($0.key, $0) }) { first, _ in first } @@ -142,41 +146,57 @@ extension HealthKitFHIRExporter { } } - /// What the record's event key does not version but its graph embeds: an ECG references its - /// symptoms' output identifiers, so their set enters the fingerprint. - var recordParts: [String] { - switch self { - case .record(.electrocardiogram), .electrocardiogramEvidence: - symptoms.map { $0.uuid.uuidString.lowercased() }.sorted() - case .record: - [] + /// An ECG record with its voltages validated into evidence, once, before the reservation; every other input, + /// and an ECG whose evidence does not validate, as given: the latter is refused when it is delivered. + var validated: Input { + guard case let .record(.electrocardiogram(ecg, voltages, symptoms)) = self, + let evidence = try? HealthKitECGEvidence(HealthKitECGRecord(electrocardiogram: ecg, voltageMeasurements: voltages)) else { + return self } + return .electrocardiogramEvidence(ecg, evidence: evidence, symptoms: symptoms) } } - /// One input and the requests it needs: one for its record, one per registered ECG symptom. + /// One input prepared before the reservation: its ECG evidence validated, and one event per sample it converts, + /// its record and each registered ECG symptom, under what the policies resolved for that sample. Each event's + /// fingerprint covers those answers and the record's companion data, and its graph is built from exactly them. struct Plan { + /// One sample's request and what the policies answered for it. + struct Event { + let request: ExchangeEventRequest + let policies: ResolvedPolicies + } + let input: Input - let primary: ExchangeEventRequest? + let primary: Event? /// One entry per correlated symptom, in the record's order; `nil` for a symptom of an unregistered type. - let symptoms: [ExchangeEventRequest?] + let symptoms: [Event?] var requests: [ExchangeEventRequest] { - [primary].compactMap(\.self) + symptoms.compactMap(\.self) + ([primary] + symptoms).compactMap { $0?.request } } var source: Export.Source { Export.Source(uuid: input.sample.uuid, typeIdentifier: input.sample.sampleType.identifier) } - init(_ input: Input, context: ExportContext) { - let primary = ExchangeEventKey.active(input.sample).map { context.request(for: $0, recordParts: input.recordParts) } + init(_ input: Input, exporter: HealthKitFHIRExporter) { + let input = input.validated + let primary = Self.event(for: input.sample, exporter: exporter) { input.companionParts } self.input = input self.primary = primary // A record that is refused outright reserves nothing for its symptoms either. - self.symptoms = primary == nil ? [] : input.symptoms.map { symptom in - ExchangeEventKey.active(symptom).map { context.request(for: $0) } + self.symptoms = primary == nil ? [] : input.symptoms.map { Self.event(for: $0, exporter: exporter) { [] } } + } + + /// The event of a sample of a registered type: its key, fingerprinted with what the policies answer for the + /// sample and with `companionParts`, computed only for such a sample. + private static func event(for sample: HKSample, exporter: HealthKitFHIRExporter, companionParts: () -> [String]) -> Event? { + guard let key = ExchangeEventKey.active(sample) else { + return nil } + let policies = ResolvedPolicies(sample, options: exporter.options) + return Event(request: exporter.context.request(for: key, recordParts: policies.fingerprintParts + companionParts()), policies: policies) } } @@ -199,7 +219,7 @@ extension HealthKitFHIRExporter { // standalone export of the same record in this call keeps its event. let set: HealthKitConversionSet? do { - set = try convert(plan, primary: reservation(for: primary, in: reserved), reserved: reserved) + set = try convert(plan, primary: primary, reserved: reserved) } catch { let failure = HealthKitConversionError(conversionFailure: error, source: plan.source.sourceType) try receive(Export(source: plan.source, outcome: .refused(failure), warnings: [])) @@ -230,14 +250,15 @@ extension HealthKitFHIRExporter { private func convert( _ plan: Plan, - primary: ExchangeEventReservation, + primary: Plan.Event, reserved: [ExchangeEventRequest: ExchangeEventReservation] ) throws -> HealthKitConversionSet? { - let request = try request(for: plan.input.sample, reservation: primary) + let request = try request(for: plan.input.sample, policies: primary.policies, reservation: reservation(for: primary.request, in: reserved)) switch plan.input { case .record(.sample(let sample)): return try assembly.convert(sample, request: request) case let .record(.electrocardiogram(ecg, voltages, symptoms)): + // Its evidence did not validate when it was planned: validating it again refuses it for the same reason. return try assembly.convertECG( ecg, evidence: HealthKitECGEvidence(HealthKitECGRecord(electrocardiogram: ecg, voltageMeasurements: voltages)), @@ -266,11 +287,11 @@ extension HealthKitFHIRExporter { reserved: [ExchangeEventRequest: ExchangeEventReservation] ) throws -> [UUID: HealthKitAssembly.Request] { var requests: [UUID: HealthKitAssembly.Request] = [:] - for (symptom, planned) in zip(plan.input.symptoms, plan.symptoms) { - guard let planned, requests[symptom.uuid] == nil else { + for (symptom, event) in zip(plan.input.symptoms, plan.symptoms) { + guard let event, requests[symptom.uuid] == nil else { continue } - requests[symptom.uuid] = try request(for: symptom, reservation: reservation(for: planned, in: reserved)) + requests[symptom.uuid] = try request(for: symptom, policies: event.policies, reservation: reservation(for: event.request, in: reserved)) } return requests } @@ -289,10 +310,10 @@ extension HealthKitFHIRExporter { @available(iOS 18, macOS 15, watchOS 11, *) extension HealthKitFHIRExporter { - /// One record's event, the facts frozen with it, and the policies the options resolve for its source. - func request(for sample: HKSample, reservation: ExchangeEventReservation) throws -> HealthKitAssembly.Request { - let source = sample.sourceRevision.source - return HealthKitAssembly.Request( + /// One record's event, the facts frozen with it, and the policies in force, with the answers resolved for its + /// sample before the reservation, which its fingerprint covers. + func request(for sample: HKSample, policies: ResolvedPolicies, reservation: ExchangeEventReservation) throws -> HealthKitAssembly.Request { + HealthKitAssembly.Request( event: try ExchangeEventIdentifier( system: producer.identityScope.systems.event, producerInstance: reservation.producerInstance, @@ -304,8 +325,8 @@ extension HealthKitFHIRExporter { converterRole: options.role.converterRole(for: sample.sourceRevision, application: reservation.facts.application), repositoryIDs: try legacyRepositoryIDs(for: sample.uuid), options: HealthKitConversionOptions( - writer: options.writer.classification(of: source), - recordingDevice: options.recordingDevice.resolver, + writer: policies.writer, + recordingDevice: ResolvedRecordingDevice(device: policies.recordingDevice), udiDisclosure: options.udi == .authorized ? .authorizedUDI : .omit, routeDisclosure: options.route == .authorized ? .authorized : .omit, nativeIdentifierDisclosure: options.nativeIdentifier diff --git a/Tests/GroveHealthKitFHIRTests/ExporterCompanionFingerprintTests.swift b/Tests/GroveHealthKitFHIRTests/ExporterCompanionFingerprintTests.swift new file mode 100644 index 000000000..c74275263 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ExporterCompanionFingerprintTests.swift @@ -0,0 +1,207 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import CoreLocation +import Foundation +@testable import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit +import Testing + + +/// A deployment resolver that names every device by one fixed per-unit token and name. +private struct FixedUnitResolver: RecordingDeviceResolver { + let token: String + var name = "Apple Watch" + + func recordingDevice(for device: HKDevice) -> RecordingDevice? { + try? RecordingDevice(stableUnitToken: token, name: name) + } +} + + +/// A resolver whose first answer is `unit-a` and every later one `unit-b`, as one reading mutable pairing state. +private final class FirstAnswerResolver: RecordingDeviceResolver, @unchecked Sendable { // `answered` is guarded by `lock`. + private let lock = NSLock() + private var answered = false + + func recordingDevice(for device: HKDevice) -> RecordingDevice? { + lock.lock() + let token = answered ? "unit-b" : "unit-a" + answered = true + lock.unlock() + return try? RecordingDevice(stableUnitToken: token, name: "Apple Watch") + } +} + + +/// The IG's retry rule (`catalog/exchange-protocol.json`, `event.retry`): an exact retry reuses the event, and any +/// content change receives a new sequence. Each case exports a record, drops the receipt unreleased (its hold +/// lapses, the reservation stays, as after a failed upload), then redelivers the same sample with one input that +/// changes the graph bytes: companion data, or what a policy closure answers for the record. +@Suite +struct ExporterCompanionFingerprintTests { + private typealias Fixtures = ExporterFixtures + + private static let beats = [ + HealthKitHeartbeat(timeSinceSeriesStart: 0, precededByGap: false), + HealthKitHeartbeat(timeSinceSeriesStart: 0.84, precededByGap: false), + HealthKitHeartbeat(timeSinceSeriesStart: 1.71, precededByGap: true) + ] + + /// The primary export of one call; the receipt is dropped without release, so the reservation stays. + private static func primary( + _ exporter: HealthKitFHIRExporter, + _ input: HealthKitFHIRExporter.Input + ) throws -> HealthKitFHIRExporter.Export { + let (exports, _) = try Fixtures.collect(exporter, [input]) + return try #require(exports.first) + } + + /// An exact redelivery reuses the event byte for byte; a redelivery whose bytes changed must not reuse it. + private static func expectNoReuse( + original: HealthKitFHIRExporter.Export, + exact: HealthKitFHIRExporter.Export, + changed: HealthKitFHIRExporter.Export, + sourceLocation: SourceLocation = #_sourceLocation + ) throws { + let originalJSON = try #require(original.graph?.json, "original: \(original.outcome)", sourceLocation: sourceLocation) + let changedJSON = try #require(changed.graph?.json, "changed: \(changed.outcome)", sourceLocation: sourceLocation) + try #require(exact.event == original.event, "an exact redelivery reuses the event", sourceLocation: sourceLocation) + try #require(exact.graph?.json == originalJSON, "an exact redelivery is byte-identical", sourceLocation: sourceLocation) + try #require(changedJSON != originalJSON, "the companion change must change the graph bytes", sourceLocation: sourceLocation) + #expect( + changed.event != original.event, + "event sequence \(original.sequence ?? "nil") was reused for different graph bytes", + sourceLocation: sourceLocation + ) + } + + @Test("Beats: one changed beat under a reserved heartbeat series takes a new sequence") + func changedBeatTakesANewSequence() throws { + let exporter = try Fixtures.exporter() + let series = try StoredSampleFixtures.seriesSample( + HKHeartbeatSeriesSample.self, + sampleType: HKSeriesType.heartbeat(), + shape: GoldenCase.seriesShape(uuid: 0xF0, duration: 2) + ) + var changedBeats = Self.beats + changedBeats[1] = HealthKitHeartbeat(timeSinceSeriesStart: 0.85, precededByGap: false) + let original = try Self.primary(exporter, .record(.heartbeatSeries(series, beats: Self.beats))) + let exact = try Self.primary(exporter, .record(.heartbeatSeries(series, beats: Self.beats))) + let changed = try Self.primary(exporter, .record(.heartbeatSeries(series, beats: changedBeats))) + try Self.expectNoReuse(original: original, exact: exact, changed: changed) + } + + @Test("Locations: one changed location under a reserved workout route takes a new sequence") + func changedLocationTakesANewSequence() throws { + let exporter = try Fixtures.exporter { $0.route = .authorized } + let route = try StoredSampleFixtures.seriesSample( + HKWorkoutRoute.self, + sampleType: HKSeriesType.workoutRoute(), + shape: GoldenCase.seriesShape(uuid: 0xF1, duration: 1) + ) + var changedLocations = GoldenCase.routeLocations + let moved = changedLocations[1] + changedLocations[1] = CLLocation( + coordinate: CLLocationCoordinate2D(latitude: moved.coordinate.latitude + 0.0001, longitude: moved.coordinate.longitude), + altitude: moved.altitude, + horizontalAccuracy: moved.horizontalAccuracy, + verticalAccuracy: moved.verticalAccuracy, + course: moved.course, + courseAccuracy: moved.courseAccuracy, + speed: moved.speed, + speedAccuracy: moved.speedAccuracy, + timestamp: moved.timestamp + ) + let original = try Self.primary(exporter, .record(.workoutRoute(route, locations: GoldenCase.routeLocations))) + let exact = try Self.primary(exporter, .record(.workoutRoute(route, locations: GoldenCase.routeLocations))) + let changed = try Self.primary(exporter, .record(.workoutRoute(route, locations: changedLocations))) + try Self.expectNoReuse(original: original, exact: exact, changed: changed) + } + + /// `HKElectrocardiogram.VoltageMeasurement` cannot be built outside HealthKit, so the voltages arrive through the + /// evidence seam, whose record parts are the same as the public `.electrocardiogram` record's: the symptoms only. + @Test("Voltages: one changed voltage under a reserved ECG takes a new sequence") + func changedVoltageTakesANewSequence() throws { + let exporter = try Fixtures.exporter() + let (ecg, evidence) = try GoldenCase.electrocardiogramEvidence(uuid: 0xF2, symptomsPresent: false) + let changedWaveform = try HealthKitECGEvidenceValidator.validateWaveform( + reportedCount: evidence.source.numberOfVoltageMeasurements, + samplingFrequencyHertz: evidence.source.samplingFrequency, + points: [ + HealthKitECGVoltagePoint(timeSinceSampleStart: 0.250, millivolts: 0.125), + HealthKitECGVoltagePoint(timeSinceSampleStart: 0.252, millivolts: 0.375), + HealthKitECGVoltagePoint(timeSinceSampleStart: 0.254, millivolts: -0.125), + HealthKitECGVoltagePoint(timeSinceSampleStart: 0.256, millivolts: 0) + ] + ) + let changedEvidence = HealthKitECGEvidence(source: evidence.source, waveform: changedWaveform) + let original = try Self.primary(exporter, .electrocardiogramEvidence(ecg, evidence: evidence, symptoms: [])) + let exact = try Self.primary(exporter, .electrocardiogramEvidence(ecg, evidence: evidence, symptoms: [])) + let changed = try Self.primary(exporter, .electrocardiogramEvidence(ecg, evidence: changedEvidence, symptoms: [])) + try Self.expectNoReuse(original: original, exact: exact, changed: changed) + } + + /// Two exporters over one ledger, as before and after an app update that changed what its resolver returns. + @Test("Custom resolver: a resolver naming another device under a reserved record takes a new sequence") + func changedCustomResolverTakesANewSequence() throws { + let sequencer = ExchangeEventSequencer.inMemory() + let before = try Fixtures.exporter(sequencer: sequencer) { $0.recordingDevice = .custom(FixedUnitResolver(token: "unit-a")) } + let after = try Fixtures.exporter(sequencer: sequencer) { $0.recordingDevice = .custom(FixedUnitResolver(token: "unit-b")) } + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0xF3), device: GoldenFixtures.watch, writer: GoldenFixtures.foreignWriter) + let original = try Self.primary(before, .record(.sample(sample))) + let exact = try Self.primary(before, .record(.sample(sample))) + let changed = try Self.primary(after, .record(.sample(sample))) + try Self.expectNoReuse(original: original, exact: exact, changed: changed) + } + + @Test("Custom resolver: a resolver naming the same unit otherwise under a reserved record takes a new sequence") + func renamedCustomResolverTakesANewSequence() throws { + let sequencer = ExchangeEventSequencer.inMemory() + let before = try Fixtures.exporter(sequencer: sequencer) { $0.recordingDevice = .custom(FixedUnitResolver(token: "unit-a")) } + let after = try Fixtures.exporter(sequencer: sequencer) { + $0.recordingDevice = .custom(FixedUnitResolver(token: "unit-a", name: "Left Wrist")) + } + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0xF4), device: GoldenFixtures.watch) + let original = try Self.primary(before, .record(.sample(sample))) + let exact = try Self.primary(before, .record(.sample(sample))) + let changed = try Self.primary(after, .record(.sample(sample))) + try Self.expectNoReuse(original: original, exact: exact, changed: changed) + } + + @Test("Classify: a closure classifying a reserved record's source otherwise takes a new sequence") + func changedClassificationTakesANewSequence() throws { + let sequencer = ExchangeEventSequencer.inMemory() + let before = try Fixtures.exporter(sequencer: sequencer) { $0.writer = .classify { _ in .application } } + let after = try Fixtures.exporter(sequencer: sequencer) { $0.writer = .classify { _ in .omit } } + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0xF5), writer: GoldenFixtures.foreignWriter) + let original = try Self.primary(before, .record(.sample(sample))) + let exact = try Self.primary(before, .record(.sample(sample))) + let changed = try Self.primary(after, .record(.sample(sample))) + try Self.expectNoReuse(original: original, exact: exact, changed: changed) + } + + /// What is fingerprinted is what is emitted: a resolver consulted again for the graph would state `unit-b` under the + /// event fingerprinted for `unit-a`, which a fixed `unit-a` resolver would then reuse with other bytes. + @Test("Custom resolver: consulted once per record, so the graph states the device its fingerprint covers") + func customResolverIsConsultedOncePerRecord() throws { + let sequencer = ExchangeEventSequencer.inMemory() + let changing = try Fixtures.exporter(sequencer: sequencer) { $0.recordingDevice = .custom(FirstAnswerResolver()) } + let fixed = try Fixtures.exporter(sequencer: sequencer) { $0.recordingDevice = .custom(FixedUnitResolver(token: "unit-a")) } + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0xF6), device: GoldenFixtures.watch) + let first = try Self.primary(changing, .record(.sample(sample))) + let again = try Self.primary(fixed, .record(.sample(sample))) + #expect(again.event == first.event, "both fingerprint unit-a") + #expect(again.graph?.json == first.graph?.json, "the first graph states unit-a, the device it was fingerprinted under") + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFingerprintTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFingerprintTests.swift index 58664c2a3..1a21a3775 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFingerprintTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterFingerprintTests.swift @@ -122,7 +122,9 @@ struct HealthKitFHIRExporterFingerprintTests { let key = try #require(ExchangeEventKey.active(sample)) let (original, _) = try Fixtures.collect(contexts[0].1, samples: [sample]) let stored = try #require(try storage.transaction { try $0.read(LedgerKey.event(key)) }) - #expect(try EventEntry(decoding: stored, key: LedgerKey.event(key)).fingerprint == contexts[0].1.context.request(for: key).fingerprint) + let planned = HealthKitFHIRExporter.Plan(.record(.sample(sample)), exporter: contexts[0].1).primary?.request + #expect(planned?.key == key) + #expect(try EventEntry(decoding: stored, key: LedgerKey.event(key)).fingerprint == planned?.fingerprint) let (unchanged, _) = try Fixtures.collect(try Fixtures.exporter(try Fixtures.producer(sequencer: ExchangeEventSequencer(storage: storage))), samples: [sample]) #expect(unchanged[0].event == original[0].event, "an equal context reuses the reservation") let (changed, _) = try Fixtures.collect(contexts[1].1, samples: [sample]) @@ -182,6 +184,25 @@ struct HealthKitFHIRExporterFingerprintTests { #expect(exporter.context.request(for: key).fingerprint == "Y9AmAuXc9kZTd8ZjijBhBS7QD_7A8w4YKQLk7RXFRig") } + /// A record's own parts follow the call parts: what the writer and recording-device policies answered for its + /// sample, then its companion data (none for a plain sample). Pinned like the call parts, so the derivation changes + /// only on purpose. + @Test("A record's parts state the policies' answers for its sample and fingerprint to a known answer") + func recordPartsAreAKnownAnswer() throws { + let exporter = try Fixtures.exporter(try Fixtures.producer(sequencer: .inMemory()), revisions: .init(assembler: 1, healthKit: 2)) { + $0.writer = .applications([GoldenFixtures.foreignWriter.bundleIdentifier]) + } + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(1), device: GoldenFixtures.watch, writer: GoldenFixtures.foreignWriter) + let policies = HealthKitFHIRExporter.ResolvedPolicies(sample, options: exporter.options) + #expect(policies.fingerprintParts == [ + "writer", "application", + "recordingDevice", "unit", "6C4B1D1E-0000-4000-8000-000000000001", "some", "Apple Watch", "some", "Apple Inc.", "some", "Watch7,12" + ]) + let planned = try #require(HealthKitFHIRExporter.Plan(.record(.sample(sample)), exporter: exporter).primary?.request) + #expect(planned.fingerprint == exporter.context.request(for: planned.key, recordParts: policies.fingerprintParts).fingerprint) + #expect(planned.fingerprint == "4ViljxvhC5STfq5O5V-a8ML-YL42xAqmwAycm0BO414") + } + @Test("G3b: the fingerprint covers every stored option, each under its own name and with its own value") @available(*, deprecated, message: "Names the transitional legacy Bundle.id case") func fingerprintCoversEveryOption() { diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterLedgerTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterLedgerTests.swift index 9667e65e7..505aac037 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterLedgerTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterLedgerTests.swift @@ -258,8 +258,8 @@ struct HealthKitFHIRExporterLedgerTests { let last = try GoldenCase.symptom(uuid: GoldenFixtures.uuid(0xA3), type: .fatigue) #expect(HealthKitSourceType(unregistered) == nil) let input = try Fixtures.electrocardiogram(uuid: 0xA0, symptoms: [first, unregistered, last]) - let plan = HealthKitFHIRExporter.Plan(input, context: exporter.context) - #expect(plan.symptoms.map { $0?.key } == [ExchangeEventKey.active(first), nil, ExchangeEventKey.active(last)]) + let plan = HealthKitFHIRExporter.Plan(input, exporter: exporter) + #expect(plan.symptoms.map { $0?.request.key } == [ExchangeEventKey.active(first), nil, ExchangeEventKey.active(last)]) let (exports, _) = try Fixtures.collect(exporter, [input]) guard case .refused(let reason) = exports[0].outcome else { Issue.record("expected a refusal, got \(exports[0].outcome)") From bf11c55c2336bd7c37863f3eb672f16d2d67de81 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 19:47:24 +0200 Subject: [PATCH 047/220] Refuse Graph Bytes Stating Values the FHIR Model Rewrites Fix-round step G1b, Codex fix-round review (G3/G1b) finding 1 (major, ig-compliance). ExchangeGraph(validating:kind:) decides every rule over the decoded model, then compared the given bytes with the model's encoding by shape only (LosslessJSONValue.shape blanked every scalar). A scalar the decoder rewrites therefore passed while the original travelled in `json`. Reproduced on c16211e7 through the public initializer: - the heart-rate-minimal golden with "|" appended to its Provenance profile was accepted and kept those bytes; the model's encoding states the profile without the "|" (FHIRModels' Canonical drops an empty version), so the rules checked the admitted profile while the bytes claim one the pinned validator refuses (mobile-exchange.provenance-profile, ig-pin/scripts/producer_validation/profiles.py:426-432); - the same golden with its decimal 72 written with 43 significant digits was accepted although the model rounds it to 72. Fix: the kept-content check compares the given bytes with the model's encoding token for token, strings and member names scalar by scalar, and numbers by their exact value (ExactNumber: sign, significant digits and power of ten, nothing rounded), so the decimal lexeme rewrite the model makes (72.0 -> 72) stays admitted and every other rewrite is refused with .invalidEntries("Serialized event carries content the model does not keep") (was "... members ..."; mobile-exchange.unclassified as before). LosslessJSONValue's token equality and the new isKept(as:) share one recursive comparison that differs only in how numbers compare, replacing the two allocated shape trees (the review's simplification note). An exponent of 2^32 or more in magnitude compares by lexeme, so no scale computation can overflow (the watchOS arm64_32 build included: Int64). Tests (ExchangeGraphBytesTests): revalidationRefusesValuesTheModelRewrites (both reproductions above refused) and keptContentComparesNumbersByExactValue (72 = 72.0 = 7.2e1 = 720E-1 = 0.0072e+4, -0.0 = 0; 7.2, -72, 720, the rounded decimal, huge exponents, a rewritten string, a boolean against a string, an extra array element and a missing member are not kept). The existing 72.0 acceptance and dropped-member refusals stay. Mutation proof (ExchangeGraphBytesTests on macOS, each reverted): exponent ignored, sign ignored, trailing zeros kept, leading zeros kept, signed zero, exponent bound removed (traps), array or object count check removed, numbers by lexeme only, strings always equal: all 10 killed. Residual, not covered: an integer element written with a fraction, such as SampledData.dimensions 1.0, is still admitted, because the model decodes it to 1 and 1.0 and 1 are one value; telling it from the decimal 72.0 needs the element's FHIR type, which the JSON comparison does not see. The pinned validator refuses it (payloads.py:91, "dimensions must be a positive integer"). Output diff: none. Producers build graphs from models and never run this check (no production caller re-validates); goldens unchanged. Gates: GroveHealthKitFHIR macOS 311 total, 310 passed, 1 skipped (the throughput benchmark); GroveFHIR 108/108; GroveSensorKitFHIR 85/85; GroveQuestionnaire 260/260; GROVE_LOWERED_DEPLOYMENT_TARGETS=1 xcrun swift build --target GroveFHIRContract: Build complete; swiftlint --strict: no findings; reuse lint: compliant. (All gates ran on the step's final tree.) Co-Authored-By: Claude Opus 5.5 --- .../ExchangeGraph+Equality.swift | 57 +++++++++++++++---- Sources/GroveFHIRContract/ExchangeGraph.swift | 19 ++++--- .../ExchangeGraphBytesTests.swift | 42 +++++++++++++- 3 files changed, 97 insertions(+), 21 deletions(-) diff --git a/Sources/GroveFHIRContract/ExchangeGraph+Equality.swift b/Sources/GroveFHIRContract/ExchangeGraph+Equality.swift index 4e95edafa..4cf1fd8f1 100644 --- a/Sources/GroveFHIRContract/ExchangeGraph+Equality.swift +++ b/Sources/GroveFHIRContract/ExchangeGraph+Equality.swift @@ -9,6 +9,32 @@ import Foundation +/// The exact value of a JSON number lexeme: its sign, its significant digits and the power of ten that scales them, so +/// `72`, `72.0` and `7.2e1` are one value and nothing is rounded. +private struct ExactNumber: Equatable { + let isNegative: Bool + let digits: Substring + let exponent: Int64 + + /// The value of a lexeme the parser admitted; `nil` for an exponent of 2^32 or more in magnitude, which then + /// compares by its lexeme alone. + init?(_ lexeme: String) { + let parts = lexeme.split(maxSplits: 1) { $0 == "e" || $0 == "E" } + guard let mantissa = parts.first, let stated = parts.count == 2 ? Int64(parts[1]) : 0, stated.magnitude < 1 << 32 else { + return nil + } + let point = mantissa.firstIndex(of: ".") + let fraction = point.map { mantissa[mantissa.index(after: $0)...] } ?? "" + let significant = (mantissa[..<(point ?? mantissa.endIndex)].drop { $0 == "-" } + fraction).drop { $0 == "0" } + let trailingZeros = significant.reversed().prefix { $0 == "0" }.count + self.digits = significant.dropLast(trailingZeros) + // Zero has neither sign nor scale, whatever its lexeme. + self.isNegative = !digits.isEmpty && mantissa.hasPrefix("-") + self.exponent = digits.isEmpty ? 0 : stated - Int64(fraction.count) + Int64(trailingZeros) + } +} + + /// A JSON document read without losing what the receiver compares: number lexemes stay text, and strings /// keep every Unicode scalar they were written with. /// @@ -271,30 +297,37 @@ indirect enum LosslessJSONValue: Equatable { extension LosslessJSONValue { - /// The value with every scalar blanked: which members and elements exist, not what they hold. - var shape: LosslessJSONValue { - switch self { - case .object(let members): .object(members.mapValues(\.shape)) - case .array(let elements): .array(elements.map(\.shape)) - case .string, .number, .boolean, .null: .null + /// Token equality, with strings, lexemes and member names compared scalar by scalar. + static func == (lhs: LosslessJSONValue, rhs: LosslessJSONValue) -> Bool { + lhs.matches(rhs) { $0.unicodeScalars.elementsEqual($1.unicodeScalars) } + } + + /// Whether `kept`, the FHIR model's encoding of what it decoded from this document, states the same content: the + /// same members, elements and scalars, with numbers compared by their exact value, as the model rewrites a decimal + /// lexeme such as `72.0` but must not round a value or rewrite any other scalar. + func isKept(as kept: LosslessJSONValue) -> Bool { + matches(kept) { given, kept in + given == kept || ExactNumber(given).map { $0 == ExactNumber(kept) } ?? false } } - /// Token equality, with strings, lexemes and member names compared scalar by scalar. - static func == (lhs: LosslessJSONValue, rhs: LosslessJSONValue) -> Bool { - switch (lhs, rhs) { + /// Token equality with numbers compared by `sameNumber`. + private func matches(_ other: LosslessJSONValue, numbers sameNumber: (String, String) -> Bool) -> Bool { + switch (self, other) { case let (.object(lhs), .object(rhs)): // A dictionary finds a member under any canonically equivalent name, so the name found is compared too. lhs.count == rhs.count && lhs.allSatisfy { name, value in guard let index = rhs.index(forKey: name) else { return false } - return rhs[index].key.unicodeScalars.elementsEqual(name.unicodeScalars) && rhs[index].value == value + return rhs[index].key.unicodeScalars.elementsEqual(name.unicodeScalars) && value.matches(rhs[index].value, numbers: sameNumber) } case let (.array(lhs), .array(rhs)): - lhs == rhs - case let (.string(lhs), .string(rhs)), let (.number(lhs), .number(rhs)): + lhs.count == rhs.count && zip(lhs, rhs).allSatisfy { $0.matches($1, numbers: sameNumber) } + case let (.string(lhs), .string(rhs)): lhs.unicodeScalars.elementsEqual(rhs.unicodeScalars) + case let (.number(lhs), .number(rhs)): + sameNumber(lhs, rhs) case let (.boolean(lhs), .boolean(rhs)): lhs == rhs case (.null, .null): diff --git a/Sources/GroveFHIRContract/ExchangeGraph.swift b/Sources/GroveFHIRContract/ExchangeGraph.swift index b59d3a555..c837b449a 100644 --- a/Sources/GroveFHIRContract/ExchangeGraph.swift +++ b/Sources/GroveFHIRContract/ExchangeGraph.swift @@ -88,8 +88,9 @@ public struct ExchangeGraph: Sendable { /// /// It applies every structural rule a built graph passes, including that each adapter output has exactly one conversion /// Provenance of its adapter; StructureDefinition and terminology conformance is the conformance lane's to prove. - /// Bytes carrying a member the FHIR model does not keep are refused: the rules decide over what the model holds, and - /// ``json`` is what travels, so such a member would travel unchecked. + /// Bytes stating anything the FHIR model does not keep, a member it drops or a value it rewrites, are refused: the + /// rules decide over what the model holds, and ``json`` is what travels, so such content would travel unchecked. + /// A decimal may differ in lexeme only, as `72.0` and `72` state one value. /// /// Serialized checks run first, because Foundation keeps only one of duplicate members and /// decoding through `Foundation.URL` could normalize an identity system or collapse a @@ -154,17 +155,19 @@ public struct ExchangeGraph: Sendable { bundle: decodedBundle, document: ValidationDocument(bundle: decodedBundle, jsonData: nil) ) - try Self.validateKeptMembers(of: jsonData, decoded: decodedBundle) + try Self.validateKeptContent(of: jsonData, decoded: decodedBundle) return (eventIdentifier, decodedBundle) } - /// Whether the bytes name exactly the members and elements the decoded model encodes; values may differ in - /// lexeme only, as the model rewrites a decimal such as `72.0`. - private static func validateKeptMembers(of jsonData: Data, decoded bundle: ModelsR4.Bundle) throws(ExchangeGraphError) { + /// Whether the bytes state exactly what the decoded model encodes: the same members, elements and scalars. A number + /// may differ in lexeme only, as the model rewrites a decimal such as `72.0`; a value the model rewrote, such as a + /// canonical whose empty version it dropped or a decimal it rounded, is refused, as the rules decided over the + /// rewritten value. + private static func validateKeptContent(of jsonData: Data, decoded bundle: ModelsR4.Bundle) throws(ExchangeGraphError) { guard let given = try? LosslessJSONValue(parsing: jsonData), let kept = try? LosslessJSONValue(parsing: wireEncoder.encode(bundle)), - given.shape == kept.shape else { - throw .invalidEntries("Serialized event carries members the model does not keep") + given.isKept(as: kept) else { + throw .invalidEntries("Serialized event carries content the model does not keep") } } diff --git a/Tests/GroveHealthKitFHIRTests/ExchangeGraphBytesTests.swift b/Tests/GroveHealthKitFHIRTests/ExchangeGraphBytesTests.swift index 1ede03eee..a50f559d7 100644 --- a/Tests/GroveHealthKitFHIRTests/ExchangeGraphBytesTests.swift +++ b/Tests/GroveHealthKitFHIRTests/ExchangeGraphBytesTests.swift @@ -78,7 +78,7 @@ struct ExchangeGraphBytesTests { try change(&bundle) return try JSONSerialization.data(withJSONObject: bundle, options: [.sortedKeys, .withoutEscapingSlashes]) } - let refusal = ExchangeGraphError.invalidEntries("Serialized event carries members the model does not keep") + let refusal = ExchangeGraphError.invalidEntries("Serialized event carries content the model does not keep") #expect(throws: refusal) { try ExchangeGraph(validating: try edited { $0["note"] = "not a Bundle element" }, kind: graph.kind) } @@ -96,6 +96,46 @@ struct ExchangeGraphBytesTests { #expect(try ExchangeGraph(validating: rewritten, kind: graph.kind).json == rewritten) } + /// The rules decide over the values the model holds, so bytes stating a value the model rewrote are refused: a + /// profile canonical with an empty version, which the model drops and the IG refuses as a profile claim, and a + /// decimal beyond the model's precision, which it rounds. + @Test("Re-validation refuses values the FHIR model rewrites") + func revalidationRefusesValuesTheModelRewrites() throws { + let graph = try #require(GoldenCase.all.first).output().graph + let json = String(decoding: graph.json, as: UTF8.self) + let rewrites = [ + (#"healthkit-conversion-provenance""#, #"healthkit-conversion-provenance|""#), + (#""value":72}"#, #""value":72.00000000000000000000000000000000000000001}"#) + ] + for (original, rewritten) in rewrites { + let edited = json.replacingOccurrences(of: original, with: rewritten) + #expect(edited != json) + #expect(throws: ExchangeGraphError.invalidEntries("Serialized event carries content the model does not keep")) { + try ExchangeGraph(validating: Data(edited.utf8), kind: graph.kind) + } + } + } + + /// What re-validation compares: numbers by their exact value, every other scalar by its tokens. + @Test("Kept content compares numbers by exact value and every other scalar as given") + func keptContentComparesNumbersByExactValue() throws { + func tokens(_ json: String) throws -> LosslessJSONValue { + try LosslessJSONValue(parsing: Data(json.utf8)) + } + for lexeme in ["72", "72.0", "7.2e1", "720E-1", "0.0072e+4"] { + #expect(try tokens(lexeme).isKept(as: tokens("72")), "\(lexeme)") + } + #expect(try tokens("-0.0").isKept(as: tokens("0"))) + // An exponent of 2^32 or more in magnitude compares by its lexeme, so no scale computation overflows. + for lexeme in ["7.2", "-72", "720", "72.00000000000000000000000000000000000000001", "72e4294967296", "1.5e-9223372036854775808"] { + #expect(try !tokens(lexeme).isKept(as: tokens("72")), "\(lexeme)") + } + #expect(try !tokens(#"{"profile":"x|"}"#).isKept(as: tokens(#"{"profile":"x"}"#))) + #expect(try !tokens(#"{"flag":true}"#).isKept(as: tokens(#"{"flag":"true"}"#))) + #expect(try !tokens("[72,72]").isKept(as: tokens("[72]"))) + #expect(try !tokens("{}").isKept(as: tokens(#"{"value":72}"#))) + } + @Test("The earlier spelling forwards to the validating initializer") func earlierSpellingForwards() throws { let graph = try #require(GoldenCase.all.first).output().graph From 22dafd5ad96eddc0ce0d270fae4727dd52e30b7b Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 19:47:52 +0200 Subject: [PATCH 048/220] State That a Policy Closure Is Consulted per Input and Pin Its Refusals Fix-round step G1b review findings R1 (low, docs accuracy) and R2(c) (low, test coverage) on c16211e7. R1: WriterPolicy.classify and RecordingDevicePolicy.custom promised that the closure "is consulted once per record and call". Every Plan resolves ResolvedPolicies for its own sample and for each ECG companion symptom, so a record named by two inputs is consulted twice (reproduced on c16211e7: export([s, s]) consulted a counting classifier 2 times; [ECG with symptom S, S] 3 times). The behaviour is right and stays: a closure answering otherwise within a call refuses the later input as conflictingDuplicate, as HealthKitConversionError.conflictingDuplicate already documents, and never restates an event with other bytes. Memoizing the answers by sample UUID was rejected: it would apply one HKSample's answer to another object carrying the same UUID with another source or device, and it changes a refusal into a graph. The docs now say the closure (for .custom: for the HKDevice of) every input that names a record is consulted, an ECG's correlated symptoms included, before the call reserves any event, and that an answer changing within a call refuses the later input; ResolvedPolicies says "resolved once per input that names it", and the resolver test's name says "per input". The c16211e7 commit body and spec section 9's closure residual keep the older wording (the spec is the orchestrator's). R2(c): the symptom half of the conflictingDuplicate guard (plan.requests.allSatisfy at HealthKitFHIRExporter.swift:213) survived every committed test (H20: checking only the primary request). Under it, a standalone symptom followed by an ECG correlating that symptom under a flipped classifier answer reaches reservation(for:) and traps ("Every planned request is reserved in the same call."). New tests in HealthKitFHIRExporterBatchRetryTests: - classifierIsConsultedPerInput pins the documented counts (2, then 5) and that both inputs of one record share its event; - changedAnswerWithinACallRefusesTheLaterInput(throughElectrocardiogram:) refuses the later input, the record itself or an ECG correlating it, with conflictingDuplicate while the first keeps its graph. Mutation proof (HealthKitFHIRExporterBatchRetryTests on macOS, reverted): H20 crashes the suite. Both tests pass on the unmutated tree. Output diff: none (doc comments and tests only; goldens unchanged). Gates: GroveHealthKitFHIR macOS 311 total, 310 passed, 1 skipped (the throughput benchmark); swiftlint --strict: no findings; reuse lint: compliant. Co-Authored-By: Claude Opus 5.5 --- .../HealthKitFHIRExporter+Fingerprint.swift | 4 +- .../HealthKitFHIRExporter+Options.swift | 16 +++-- .../ExporterCompanionFingerprintTests.swift | 4 +- ...HealthKitFHIRExporterBatchRetryTests.swift | 70 ++++++++++++++++++- 4 files changed, 83 insertions(+), 11 deletions(-) diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift index edace5140..179c16a63 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Fingerprint.swift @@ -102,8 +102,8 @@ extension HealthKitFHIRExporter.Options { @available(iOS 18, macOS 15, watchOS 11, *) extension HealthKitFHIRExporter { - /// What the writer and recording-device policies answer for one sample, resolved once, before its event is - /// reserved: the event's fingerprint covers these answers and its graph states them, so a + /// What the writer and recording-device policies answer for one sample, resolved once per input that names it, + /// before its event is reserved: the event's fingerprint covers these answers and its graph states them, so a /// ``WriterPolicy/classify(_:)`` closure or a custom ``RecordingDevicePolicy`` resolver that answers otherwise /// for a reserved record takes a new sequence instead of restating the reserved event. struct ResolvedPolicies: ExchangeContextFingerprinted { diff --git a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift index 66ba06678..6a87e3753 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitFHIRExporter+Options.swift @@ -77,9 +77,11 @@ extension HealthKitFHIRExporter { /// identifier states none either, and one whose bundle identifier is not a valid Apple bundle identifier /// is refused with ``HealthKitConversionError/sourceApplicationInvalid``. case applications(Set) - /// The caller classifies each source. The closure is consulted once per record and call, before the - /// record's event is reserved, and the event's fingerprint covers its answer: an answer that changes for a - /// reserved record takes a new sequence rather than restating that event's writer. + /// The caller classifies each source. The closure is consulted for every input that names a record, an ECG's + /// correlated symptoms included, before the call reserves any event, and the event's fingerprint covers its + /// answer: an answer that changes for a reserved record takes a new sequence rather than restating that + /// event's writer, and one that changes within a call refuses the later input as + /// ``HealthKitConversionError/conflictingDuplicate``. case classify(@Sendable (HKSource) -> HealthKitWriter) /// The classification of one source under this policy. @@ -102,9 +104,11 @@ extension HealthKitFHIRExporter { case localIdentifier /// Never emit a recording Device from `HKDevice`. case omit - /// The deployment's own resolver. It is consulted once per record and call, before the record's event is - /// reserved, and the event's fingerprint covers the device it names: a resolver whose answer changes for a - /// reserved record takes a new sequence rather than restating that event's recording Device. + /// The deployment's own resolver. It is consulted for the `HKDevice` of every input that names a record, an + /// ECG's correlated symptoms included, before the call reserves any event, and the event's fingerprint covers + /// the device it names: a resolver whose answer changes for a reserved record takes a new sequence rather than + /// restating that event's recording Device, and one whose answer changes within a call refuses the later input + /// as ``HealthKitConversionError/conflictingDuplicate``. case custom(any RecordingDeviceResolver) /// The unit this policy resolves `device` to. diff --git a/Tests/GroveHealthKitFHIRTests/ExporterCompanionFingerprintTests.swift b/Tests/GroveHealthKitFHIRTests/ExporterCompanionFingerprintTests.swift index c74275263..82e8c1c9f 100644 --- a/Tests/GroveHealthKitFHIRTests/ExporterCompanionFingerprintTests.swift +++ b/Tests/GroveHealthKitFHIRTests/ExporterCompanionFingerprintTests.swift @@ -191,8 +191,8 @@ struct ExporterCompanionFingerprintTests { /// What is fingerprinted is what is emitted: a resolver consulted again for the graph would state `unit-b` under the /// event fingerprinted for `unit-a`, which a fixed `unit-a` resolver would then reuse with other bytes. - @Test("Custom resolver: consulted once per record, so the graph states the device its fingerprint covers") - func customResolverIsConsultedOncePerRecord() throws { + @Test("Custom resolver: consulted once per input, so the graph states the device its fingerprint covers") + func customResolverIsConsultedOncePerInput() throws { let sequencer = ExchangeEventSequencer.inMemory() let changing = try Fixtures.exporter(sequencer: sequencer) { $0.recordingDevice = .custom(FirstAnswerResolver()) } let fixed = try Fixtures.exporter(sequencer: sequencer) { $0.recordingDevice = .custom(FixedUnitResolver(token: "unit-a")) } diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterBatchRetryTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterBatchRetryTests.swift index 0b4a2c76f..a40a6ef86 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterBatchRetryTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterBatchRetryTests.swift @@ -15,7 +15,36 @@ import HealthKit import Testing -/// An exact retry, before release, of a call that names one record twice with different content. +/// A writer classifier that counts its consultations and answers `.application`, or, when it `flips`, `.omit` to every +/// consultation after the first, as one reading mutable state. +private final class CountingClassifier: @unchecked Sendable { // `consultations` is guarded by `lock`. + let flips: Bool + private let lock = NSLock() + private var consultations = 0 + + var count: Int { + lock.lock() + let count = consultations + lock.unlock() + return count + } + + init(flips: Bool) { + self.flips = flips + } + + func classify(_ source: HKSource) -> HealthKitWriter { + lock.lock() + consultations += 1 + let isFirst = consultations == 1 + lock.unlock() + return isFirst || !flips ? .application : .omit + } +} + + +/// A call that names one record twice: an exact retry before release, with different content, and what the policy +/// closures answer for each input. @Suite struct HealthKitFHIRExporterBatchRetryTests { private typealias Fixtures = ExporterFixtures @@ -74,6 +103,45 @@ struct HealthKitFHIRExporterBatchRetryTests { first.receipt.release() retry.receipt.release() } + + @Test("A classify closure is consulted once per input naming a record, an ECG's symptoms included") + func classifierIsConsultedPerInput() throws { + let classifier = CountingClassifier(flips: false) + let exporter = try Fixtures.exporter { $0.writer = .classify { classifier.classify($0) } } + let sample = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0xC5), writer: GoldenFixtures.foreignWriter) + let twice = try Fixtures.collect(exporter, samples: [sample, sample]) + #expect(classifier.count == 2) + #expect(twice.exports.count == 2 && twice.exports[0].event == twice.exports[1].event) + let symptom = try GoldenCase.symptom(uuid: GoldenFixtures.uuid(0xC7)) + let named = try Fixtures.collect(exporter, [Fixtures.electrocardiogram(uuid: 0xC6, symptoms: [symptom]), .record(.sample(symptom))]) + // The ECG, its symptom inside the ECG's input, and the standalone symptom. + #expect(classifier.count == 5) + let symptomEvents = named.exports.filter { $0.source.uuid == symptom.uuid }.map(\.event) + #expect(symptomEvents.count == 2 && symptomEvents[0] == symptomEvents[1]) + twice.receipt.release() + named.receipt.release() + } + + /// The later input names the symptom itself or correlates it with an ECG; either way it is refused, and no event is + /// restated with another writer. + @Test("A closure answering otherwise for a record the call named before refuses the later input", arguments: [false, true]) + func changedAnswerWithinACallRefusesTheLaterInput(throughElectrocardiogram: Bool) throws { + let classifier = CountingClassifier(flips: true) + let exporter = try Fixtures.exporter { $0.writer = .classify { classifier.classify($0) } } + let symptom = try GoldenCase.symptom(uuid: GoldenFixtures.uuid(0xC9)) + let later: HealthKitFHIRExporter.Input = try throughElectrocardiogram + ? Fixtures.electrocardiogram(uuid: 0xC8, symptoms: [symptom]) + : .record(.sample(symptom)) + let (exports, receipt) = try Fixtures.collect(exporter, [.record(.sample(symptom)), later]) + try #require(exports.count == 2) + #expect(exports[0].graph != nil) + guard case .refused(let reason) = exports[1].outcome else { + Issue.record("expected the later input to be refused, got \(exports[1].outcome)") + return + } + #expect(reason == .conflictingDuplicate) + receipt.release() + } } #endif From 48911aa0654d2fdbf00947d8276bf87ca4f6a6ba Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sun, 4 Oct 2026 19:48:07 +0200 Subject: [PATCH 049/220] Pin a Release Handed Over to a Reserve the Storage Discards Fix-round step G1b review finding R2(a, b) (low, test coverage) on c16211e7. HoldRegistry.endReserving drops the Hold(live: 0) placeholder a hand-over created once the last reserve that noted the handle ends without taking its hold (ExchangeEventSequencer+Holds.swift:69). Two mutants of that line survived GroveFHIR (106) and GroveHealthKitFHIR (307), reproduced for GroveFHIR on c16211e7 (106/106 pass under each): - C3, never dropping the placeholder: the handle reads as held forever, so no later release removes the reservation, and the entry leaks; - C12, dropping it while another reserve of the handle is still pending: the release mark is lost, and when that reuse lapses unreleased the reservation is orphaned. The code at head is correct in both cases. GateStorage gains a third point, afterDiscard: the transaction's body runs (and notes what its call is about to hold) in an attempt the storage then discards, the gate blocks, and the transaction throws Discarded, as a storage that fails a reserve after running its body does. New tests in ExchangeEventHoldRaceTests: - handOverToADiscardedReserveEnds: a release finds a reserve that noted the reservation; the storage discards that reserve; the hand-over ends with it (not held), the reservation stays as after a failed release, and a later exact reserve and release removes it; - handOverSurvivesADiscardedReserveWhileAnotherIsPending: a second reserve noted the handle (by hand, as a committed reuse not yet holding); the discarded reserve ends, the pending one takes its hold and lapses unreleased, and that lapse removes the reservation. Mutation proof (ExchangeEventHoldRaceTests on macOS, each reverted): C3 fails the first test, C12 the second; both pass unmutated. Output diff: none (tests only). Gates: GroveFHIR macOS 108/108; GroveHealthKitFHIR macOS 311 total, 310 passed, 1 skipped (the throughput benchmark); swiftlint --strict on Tests/GroveFHIRTests: no findings; reuse lint: compliant. Size (A): code 11,310 (+1,605), public 1,008 (+135) Co-Authored-By: Claude Opus 5.5 --- .../ExchangeEventHoldRaceTests.swift | 76 ++++++++++++++++++- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldRaceTests.swift b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldRaceTests.swift index 1363f4d66..a4a978889 100644 --- a/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldRaceTests.swift +++ b/Tests/GroveFHIRTests/ExchangeLedger/ExchangeEventHoldRaceTests.swift @@ -12,16 +12,21 @@ import Foundation import Testing -/// Forwards to a storage and blocks the next transaction until signalled, before it starts or after it committed, -/// so a test can run another call in between. +/// Forwards to a storage and blocks the next transaction until signalled, before it starts, after it committed or after +/// the storage discarded it, so a test can run another call in between. private final class GateStorage: ExchangeEventSequencer.Storage, @unchecked Sendable { // `gate` is guarded by `lock`. enum Point { /// Before the transaction starts. case before /// After the transaction committed, before it returns to the sequencer. case afterCommit + /// After the transaction's body ran in an attempt the storage then discarded; the transaction throws `Discarded`. + case afterDiscard } + /// What a transaction gated after its discard throws. + struct Discarded: Error {} + let base: any ExchangeEventSequencer.Storage /// Signalled when the gated transaction reaches its point. let entered = DispatchSemaphore(value: 0) @@ -50,6 +55,15 @@ private final class GateStorage: ExchangeEventSequencer.Storage, @unchecked Send if gated == .before { wait() } + if gated == .afterDiscard { + // The body runs, and notes what its call is about to hold, in an attempt that commits nothing. + _ = try? base.transaction { transaction -> R in + _ = try body(transaction) + throw Discarded() + } + wait() + throw Discarded() + } let result = try base.transaction(body) if gated == .afterCommit { wait() @@ -313,4 +327,62 @@ struct ExchangeEventHoldRaceTests { #expect(!Fixtures.isHeld(first[request]?.handle, by: sequencer)) #expect(try Fixtures.stored(LedgerKey.event(request.key), in: storage.base) == nil, "a holder released it; the last finisher removes it") } + + /// A release finds a reserve that noted the reservation in an attempt the storage then discarded: the call it handed + /// the release over to never takes its hold, so the hand-over ends with that reserve instead of reading as held. + @Test("G9d: a release handed over to a reserve whose attempt the storage discards ends with that reserve") + func handOverToADiscardedReserveEnds() throws { + let storage = GateStorage() + let sequencer = Fixtures.sequencer(storage) + let request = Fixtures.request("race") + let facts = try Fixtures.facts() + let first = try sequencer.reserve([request], at: Fixtures.instant, facts: facts) + let handle = try #require(first[request]?.handle) + let failed = DispatchSemaphore(value: 0) + storage.gate(.afterDiscard) + Thread { + _ = try? sequencer.reserve([request], at: Fixtures.instant, facts: facts) + failed.signal() + }.start() + storage.entered.wait() + try sequencer.finish([handle], released: true, forgetting: []) + #expect(try Fixtures.stored(LedgerKey.event(request.key), in: storage.base) != nil, "a reserve noted it, so it stays") + storage.proceed.signal() + failed.wait() + #expect(!Fixtures.isHeld(handle, by: sequencer), "the hand-over ended with the discarded reserve") + // As after a failed release, the reservation stays until a later exact export releases it. + let again = try sequencer.reserve([request], at: Fixtures.instant, facts: facts) + #expect(again == first) + try sequencer.finish(again.values.map(\.handle), released: true, forgetting: []) + #expect(try Fixtures.stored(LedgerKey.event(request.key), in: storage.base) == nil) + } + + /// Two reserves noted the reservation when its last holder released it; the storage discards one, the other takes its + /// hold and its call lapses unreleased: the release mark survived the discarded reserve, so that lapse removes it. + @Test("G9d: a handed-over release survives a discarded reserve while another reserve of the reservation is pending") + func handOverSurvivesADiscardedReserveWhileAnotherIsPending() throws { + let storage = GateStorage() + let sequencer = Fixtures.sequencer(storage) + let request = Fixtures.request("race") + let facts = try Fixtures.facts() + let first = try sequencer.reserve([request], at: Fixtures.instant, facts: facts) + let handle = try #require(first[request]?.handle) + // A reserve whose transaction committed the reuse and that has not yet taken its hold, noted by hand. + let pending = HoldRegistry.Notes() + sequencer.holds.beginReserving([handle], in: pending) + let failed = DispatchSemaphore(value: 0) + storage.gate(.afterDiscard) + Thread { + _ = try? sequencer.reserve([request], at: Fixtures.instant, facts: facts) + failed.signal() + }.start() + storage.entered.wait() + try sequencer.finish([handle], released: true, forgetting: []) + storage.proceed.signal() + failed.wait() + sequencer.holds.endReserving(pending, acquiring: [handle]) + try sequencer.finish([handle], released: false, forgetting: []) + #expect(try Fixtures.stored(LedgerKey.event(request.key), in: storage.base) == nil, "the release mark survived") + #expect(!Fixtures.isHeld(handle, by: sequencer)) + } } From 0b662b4b14b145ae4427a5be033b5d373a63dc86 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sat, 3 Oct 2026 17:09:02 +0200 Subject: [PATCH 050/220] Add the Effective-Time and Quantity Kernels for the HealthKit Content Layer Step 7 milestone M2: the kernels the rewritten content layer builds on, added unwired next to the code they replace. GroveFHIRContract: - ExchangeInstant's CivilDate, floorDivide, civilDate(fromDays:) and padded become package so the HealthKit layer shares the integer civil arithmetic; utcLexeme is unchanged. - Locale.posix (package) builds en_US_POSIX once; GroveFHIRDecimal uses it instead of allocating a Locale per value. GroveHealthKitFHIR (internal, not yet called by production code): - HealthKitEffectiveTime: the Mobile effective dateTime and Period (milliseconds rounded half to even from 1970, offset at the unrounded instant, whole minutes within +/-18 h checked arithmetically instead of allocating a TimeZone, years 0...9999, `timezone` extension for a named zone) and the ECG exact-Decimal dateTime, both from Hinnant civil_from_days and ASCII appends instead of Calendar, String(format:) and per-call Locales. - EffectiveRule: instant, or interval with the non-zero-Period rule. - QuantityTemplate and ComponentTemplate: a contract's Quantity and component code built once; each sample only sets the value after the decimal and domain checks. Legacy calendar fallback (owner decision D2 lands separately): local times outside 1582-10-15...9999-12-31 still go through Foundation's Gregorian calendar in the same zone, as today. Foundation is Julian before the reform, era-relative before year 1 and clamps far-future years, so proleptic dates would change pre-1582 bytes (for example 1582-10-04T23:59:59Z, pinned in a test). No content corpus exists in this branch yet to enumerate, so the fallback stays and the proleptic switch gets its own commit. Failure codes are today's (.shapeInvalid for decimal, domain and lexeme failures); spec F4 changes them later. One input that traps today now throws instead: an ECG instant whose binary64 second count floors to exactly 2^63 or Int64.min (beyond year 2.9e11). That trap was Int64(floor(x)) at 2^63. Output: unchanged. Nothing in the production path calls the new kernels; the only wired change is GroveFHIRDecimal's static locale, which parses the same text with the same locale. All 42 goldens and outlines.json pass unchanged. Verification (oracle O5): HealthKitEffectiveTimeTests compares the new Mobile and ECG builders with HealthKitConverter.effectiveDateTime and exactHealthKitDateTime over a seeded SplitMix64 sweep in 13 zones (none, LA, Kolkata, Kathmandu, St Johns, Amsterdam and Monrovia LMT, Lord Howe, Chatham, Kiritimati, fixed +/-18 h and +37 s). Each zone gets years -90 through 10200, the decades around 1582 and 1970 through 2039 with half-millisecond jitter, plus an edge list: ties, .250, a repeated DST hour, year 0/9999/10000, +/-1 s through +/-2 days around the reform, Foundation's clamp, NaN, +/-inf, 1e21 and distantPast/Future. Lexemes, extensions and errors must be identical. With TEST_RUNNER_GROVE_EFFECTIVE_TIME_SWEEP=1000000 (10^6 instants per zone) there are 0 mismatches; the suite default is 3,000. A rounding-guard test pins a tie that rounds differently from 1970 than through ExchangeInstant. HealthKitQuantityTemplateTests compares templates with HealthKitConverter.fhirQuantity for every quantity and component contract in both catalogs and with the workout statistic builder, over 23 values including domain edges and non-finite inputs. Co-Authored-By: Claude Opus 5.5 --- .../GroveFHIRContract/ExchangeInstant.swift | 19 +- .../GroveFHIRContract/GroveFHIRDecimal.swift | 11 +- .../HealthKitEffectiveTime.swift | 203 ++++++++++++++++ .../HealthKitQuantityTemplate.swift | 77 ++++++ .../HealthKitEffectiveTimeTests.swift | 223 ++++++++++++++++++ .../HealthKitQuantityTemplateTests.swift | 102 ++++++++ 6 files changed, 624 insertions(+), 11 deletions(-) create mode 100644 Sources/GroveHealthKitFHIR/HealthKitEffectiveTime.swift create mode 100644 Sources/GroveHealthKitFHIR/HealthKitQuantityTemplate.swift create mode 100644 Tests/GroveHealthKitFHIRTests/HealthKitEffectiveTimeTests.swift create mode 100644 Tests/GroveHealthKitFHIRTests/HealthKitQuantityTemplateTests.swift diff --git a/Sources/GroveFHIRContract/ExchangeInstant.swift b/Sources/GroveFHIRContract/ExchangeInstant.swift index 74a55c2b6..a1333fba1 100644 --- a/Sources/GroveFHIRContract/ExchangeInstant.swift +++ b/Sources/GroveFHIRContract/ExchangeInstant.swift @@ -20,10 +20,14 @@ package import ModelsR4 /// fraction zeros are dropped, and a whole second carries no fraction: `2026-10-03T10:30:00Z`, `…:00.5Z`, /// `…:00.251Z`. package enum ExchangeInstant { - private struct CivilDate { - let year: Int64 - let month: Int64 - let day: Int64 + /// A proleptic Gregorian calendar date. + package struct CivilDate: Equatable, Sendable { + /// The astronomical year: 0 is 1 BC. + package let year: Int64 + /// The month, 1 through 12. + package let month: Int64 + /// The day of the month, 1 through 31. + package let day: Int64 } /// `Date` counts from 2001-01-01T00:00:00Z; the wire counts from 1970. @@ -90,7 +94,8 @@ package enum ExchangeInstant { return Date(timeIntervalSinceReferenceDate: Double(overflow ? .min : sinceReference) / 1000) } - private static func floorDivide(_ value: Int64, by divisor: Int64) -> (quotient: Int64, remainder: Int64) { + /// Division rounding toward negative infinity, so the remainder is never negative for a positive divisor. + package static func floorDivide(_ value: Int64, by divisor: Int64) -> (quotient: Int64, remainder: Int64) { var quotient = value / divisor var remainder = value % divisor if remainder < 0 { @@ -101,7 +106,7 @@ package enum ExchangeInstant { } /// Days since 1970-01-01 to a proleptic Gregorian date (Howard Hinnant's `civil_from_days`). - private static func civilDate(fromDays days: Int64) -> CivilDate { + package static func civilDate(fromDays days: Int64) -> CivilDate { let shifted = days + 719_468 let era = (shifted >= 0 ? shifted : shifted - 146_096) / 146_097 let dayOfEra = shifted - era * 146_097 @@ -114,7 +119,7 @@ package enum ExchangeInstant { } /// ASCII decimal digits, zero-padded to `width`; `String(_:)` never consults the locale. - private static func padded(_ value: Int64, width: Int) -> String { + package static func padded(_ value: Int64, width: Int) -> String { let digits = String(value.magnitude) let zeros = String(repeating: "0", count: max(0, width - digits.count)) return (value < 0 ? "-" : "") + zeros + digits diff --git a/Sources/GroveFHIRContract/GroveFHIRDecimal.swift b/Sources/GroveFHIRContract/GroveFHIRDecimal.swift index 5e29af33d..2e7ab1a02 100644 --- a/Sources/GroveFHIRContract/GroveFHIRDecimal.swift +++ b/Sources/GroveFHIRContract/GroveFHIRDecimal.swift @@ -34,13 +34,16 @@ public struct GroveFHIRDecimal: Hashable, Sendable { // Decimal-to-Double conversion is inexact for ordinary values such as 36.52 and would // refuse them. let lexical = String(groveFHIRPlainDecimal: value) - guard let decimal = Decimal( - string: lexical, - locale: Locale(identifier: "en_US_POSIX") - ), Double(lexical) == value else { + guard let decimal = Decimal(string: lexical, locale: .posix), Double(lexical) == value else { throw .outsideFHIRDecimalDomain(lexical) } self.lexical = lexical self.decimal = decimal } } + + +extension Locale { + /// The fixed `en_US_POSIX` locale, built once, for reading and writing machine-readable numbers. + package static let posix = Locale(identifier: "en_US_POSIX") +} diff --git a/Sources/GroveHealthKitFHIR/HealthKitEffectiveTime.swift b/Sources/GroveHealthKitFHIR/HealthKitEffectiveTime.swift new file mode 100644 index 000000000..8bdabfddd --- /dev/null +++ b/Sources/GroveHealthKitFHIR/HealthKitEffectiveTime.swift @@ -0,0 +1,203 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import FHIRModelsExtensions +import Foundation +import GroveFHIRContract +import ModelsR4 + + +/// How a measurement's effective time is drawn from a HealthKit sample's start and end. +@available(iOS 18, macOS 15, watchOS 11, *) +enum EffectiveRule: Hashable, Sendable { + /// `effectiveDateTime` at the sample's start. + case instant + /// `effectivePeriod` from start to end; a reversed interval never qualifies, and a zero-width one + /// qualifies only when the measurement does not require a non-zero Period. FHIR `per-1` admits + /// `start == end`, so a point-in-time source keeps its instant as an equal-endpoint Period. + case interval(nonZero: Bool) + + /// The effective value for a sample spanning `start` to `end` in the source's `zone`. + func value(start: Date, end: Date, zone: TimeZone?) throws(HealthKitValueFailure) -> Observation.EffectiveX { + switch self { + case .instant: + return .dateTime(try HealthKitEffectiveTime.dateTime(start, zone: zone)) + case let .interval(nonZero): + guard end > start || (end == start && !nonZero) else { + throw .effectivePeriodInvalid + } + return .period(try HealthKitEffectiveTime.period(start: start, end: end, zone: zone)) + } + } +} + + +/// FHIR date-times for HealthKit instants, built from integer civil arithmetic instead of a `Calendar`. +/// +/// Mobile effective instants round to the millisecond, ties to even, counted from 1970 — never through +/// ``ExchangeInstant``, whose milliseconds count from `Date`'s 2001 reference and so round other ties. +/// They keep the source zone's offset at the unrounded instant, print `.mmm` untrimmed, and write a +/// zero offset as `Z`. ECG timing instead keeps exact Decimal seconds (``exactDateTime(_:offset:zone:)``). +/// +/// Local times outside 1582-10-15 through 9999 take Foundation's Gregorian calendar, which switches to +/// the Julian calendar before the 1582 reform and clamps far-future years, so those instants keep the +/// bytes they have always had. +@available(iOS 18, macOS 15, watchOS 11, *) +enum HealthKitEffectiveTime { + /// Wall-clock fields of one local second. + private struct CivilTime { + let year: Int + let month: Int + let day: Int + let hour: Int + let minute: Int + let second: Int + } + + /// Local seconds since 1970 from 1582-10-15T00:00 through 9999-12-31T23:59:59, where Foundation's + /// Gregorian calendar is proleptic Gregorian and `civil_from_days` agrees with it. + private static let arithmeticWindow: Swift.Range = -12_219_292_800 ..< 253_402_300_800 + + /// The widest UTC offset Foundation represents, ±18 hours. + private static let maximumOffsetSeconds = 64_800 + + /// An effective instant in the source's own zone, which also travels as the `timezone` extension, + /// or in UTC when the source names none. + static func dateTime(_ date: Date, zone: TimeZone?) throws(HealthKitValueFailure) -> FHIRPrimitive { + guard let lexeme = mobileLexeme(date, zone: zone), let dateTime = try? DateTime(lexeme) else { + throw .shapeInvalid + } + guard let zone else { + return FHIRPrimitive(dateTime) + } + return FHIRPrimitive( + dateTime, + extension: [Extension(url: Canonicals.timezone, value: .code(zone.identifier.asFHIRStringPrimitive()))] + ) + } + + /// An effective Period in the source's zone; the end is built first, as its failures take precedence. + static func period(start: Date, end: Date, zone: TimeZone?) throws(HealthKitValueFailure) -> Period { + let end = try dateTime(end, zone: zone) + return Period(end: end, start: try dateTime(start, zone: zone)) + } + + /// An ECG instant: `date` plus an exact Decimal offset, at the zone's fixed offset for that second. + /// + /// The seconds stay exact Decimals — adding the offset through `Date` would round a second time and can + /// break SampledData's period arithmetic — and print trimmed (`00.25`). No `timezone` extension is + /// added; a fixed-offset zone keeps the second occurrence of a repeated DST hour from printing as the first. + static func exactDateTime(_ date: Date, offset: Decimal, zone: TimeZone) throws(HealthKitConversionError) -> DateTime { + let epochSeconds = date.timeIntervalSince1970 + guard epochSeconds.isFinite, + let epochDecimal = Decimal(string: String(epochSeconds), locale: .posix) else { + throw .ecgEvidence(.invalidSourcePeriod) + } + let target = epochDecimal + offset + // The floor is taken in binary64 and corrected by one second; Int64's floor has no predecessor to correct to. + guard var wholeSeconds = Int64(exactly: NSDecimalNumber(decimal: target).doubleValue.rounded(.down)), + wholeSeconds != .min else { + throw .ecgEvidence(.invalidSourcePeriod) + } + var fraction = target - Decimal(wholeSeconds) + if fraction < 0 { + wholeSeconds -= 1 + fraction += 1 + } else if fraction >= 1 { + wholeSeconds += 1 + fraction -= 1 + } + let wholeSecondDate = Date(timeIntervalSince1970: TimeInterval(wholeSeconds)) + let fixedZone = zone.fixedOffset(at: wholeSecondDate) + let fixedOffset = fixedZone.secondsFromGMT(for: wholeSecondDate) + guard let civil = civilTime(seconds: wholeSeconds, offset: fixedOffset, zone: fixedZone), + let month = UInt8(exactly: civil.month), + let day = UInt8(exactly: civil.day), + let hour = UInt8(exactly: civil.hour), + let minute = UInt8(exactly: civil.minute) else { + throw .ecgEvidence(.invalidSourcePeriod) + } + return DateTime( + date: FHIRDate(year: civil.year, month: month, day: day), + time: FHIRTime(hour: hour, minute: minute, second: Decimal(civil.second) + fraction), + timezone: fixedZone + ) + } + + /// The Mobile lexeme `YYYY-MM-DDThh:mm:ss[.mmm](Z|±hh:mm)`, or `nil` when the instant has none: + /// non-finite, beyond Int64 milliseconds, an offset that is not whole minutes within ±18 h, or a + /// local year outside 0…9999. + private static func mobileLexeme(_ date: Date, zone: TimeZone?) -> String? { + guard let milliseconds = Int64(exactly: (date.timeIntervalSince1970 * 1_000).rounded(.toNearestOrEven)) else { + return nil + } + let offset = zone?.secondsFromGMT(for: date) ?? 0 + guard offset.isMultiple(of: 60), abs(offset) <= maximumOffsetSeconds else { + return nil + } + let (wholeSeconds, millisecond) = ExchangeInstant.floorDivide(milliseconds, by: 1_000) + guard let civil = civilTime(seconds: wholeSeconds, offset: offset), (0...9_999).contains(civil.year) else { + return nil + } + var lexeme = ExchangeInstant.padded(Int64(civil.year), width: 4) + lexeme += "-" + twoDigits(civil.month) + "-" + twoDigits(civil.day) + lexeme += "T" + twoDigits(civil.hour) + ":" + twoDigits(civil.minute) + ":" + twoDigits(civil.second) + if millisecond != 0 { + lexeme += "." + ExchangeInstant.padded(millisecond, width: 3) + } + guard offset != 0 else { + return lexeme + "Z" + } + let magnitude = Int(offset.magnitude) + return lexeme + (offset < 0 ? "-" : "+") + twoDigits(magnitude / 3_600) + ":" + twoDigits(magnitude % 3_600 / 60) + } + + /// A field of at most two digits, zero-padded to two. + private static func twoDigits(_ value: Int) -> String { + ExchangeInstant.padded(Int64(value), width: 2) + } + + /// The wall-clock fields of a UTC second count at `offset` seconds from UTC; `zone`, when given, is the + /// zone stating that offset, else the fixed-offset zone of `offset`. + private static func civilTime(seconds: Int64, offset: Int, zone: TimeZone? = nil) -> CivilTime? { + let (local, overflow) = seconds.addingReportingOverflow(Int64(offset)) + guard !overflow, arithmeticWindow.contains(local) else { + return (zone ?? TimeZone(secondsFromGMT: offset)).flatMap { foundationCivilTime(seconds: seconds, zone: $0) } + } + let (days, secondOfDay) = ExchangeInstant.floorDivide(local, by: 86_400) + let date = ExchangeInstant.civilDate(fromDays: days) + return CivilTime( + year: Int(date.year), + month: Int(date.month), + day: Int(date.day), + hour: Int(secondOfDay / 3_600), + minute: Int(secondOfDay / 60 % 60), + second: Int(secondOfDay % 60) + ) + } + + /// The fields Foundation's Gregorian calendar states for a UTC second count in `zone`, including its Julian + /// dates before the reform, its era-relative years before year 1 and its clamp of far-future instants. + private static func foundationCivilTime(seconds: Int64, zone: TimeZone) -> CivilTime? { + var calendar = Calendar(identifier: .gregorian) + calendar.timeZone = zone + let parts = calendar.dateComponents( + [.year, .month, .day, .hour, .minute, .second], + from: Date(timeIntervalSince1970: TimeInterval(seconds)) + ) + guard let year = parts.year, let month = parts.month, let day = parts.day, + let hour = parts.hour, let minute = parts.minute, let second = parts.second else { + return nil + } + return CivilTime(year: year, month: month, day: day, hour: hour, minute: minute, second: second) + } +} + +#endif diff --git a/Sources/GroveHealthKitFHIR/HealthKitQuantityTemplate.swift b/Sources/GroveHealthKitFHIR/HealthKitQuantityTemplate.swift new file mode 100644 index 000000000..89917460e --- /dev/null +++ b/Sources/GroveHealthKitFHIR/HealthKitQuantityTemplate.swift @@ -0,0 +1,77 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +import GroveFHIRContract +import ModelsR4 + + +/// A contract component whose value is a quantity, built once: its code and its quantity template. +@available(iOS 18, macOS 15, watchOS 11, *) +struct ComponentTemplate: Sendable { + /// The component code, one coding without a display. + let code: CodeableConcept + /// The component's quantity. + let quantity: QuantityTemplate + + /// The template for a quantity component, or `nil` when the contract states no quantity for it. + init?(_ contract: ComponentContract) { + guard let quantity = contract.quantity else { + return nil + } + code = CodeableConcept(coding: [ + Coding(code: contract.code.asFHIRStringPrimitive(), system: FHIRPrimitive(FHIRURI(stringLiteral: contract.system))) + ]) + self.quantity = QuantityTemplate(quantity) + } + + /// The component carrying `value`. + func component(_ value: Double) throws(HealthKitValueFailure) -> ObservationComponent { + ObservationComponent(code: code, value: .quantity(try quantity.quantity(value))) + } +} + + +/// A contract's FHIR quantity built once, so each sample sets only the value. +@available(iOS 18, macOS 15, watchOS 11, *) +struct QuantityTemplate: Sendable { + /// The contract's code, system and unit, with no value. + let empty: Quantity + /// The inclusive value domain the canonical value must fall in, if the contract states one. + let domain: QuantityValueDomain? + + /// The template for one quantity contract. + init(_ contract: QuantityContract) { + empty = Quantity( + code: contract.code.asFHIRStringPrimitive(), + system: FHIRPrimitive(FHIRURI(stringLiteral: contract.system)), + unit: contract.unit.asFHIRStringPrimitive() + ) + domain = contract.valueDomain + } + + /// The quantity carrying `value` as its shortest round-trip decimal, which must lie in the domain. + func quantity(_ value: Double) throws(HealthKitValueFailure) -> Quantity { + let decimal: Decimal + do { + decimal = try GroveFHIRDecimal(value).decimal + } catch { + throw .shapeInvalid + } + guard domain?.contains(decimal) != false else { + throw .shapeInvalid + } + var quantity = empty + quantity.value = FHIRPrimitive(FHIRDecimal(decimal)) + return quantity + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitEffectiveTimeTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitEffectiveTimeTests.swift new file mode 100644 index 000000000..c3f2ac657 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/HealthKitEffectiveTimeTests.swift @@ -0,0 +1,223 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +import GroveFHIRContract +@testable import GroveHealthKitFHIR +import ModelsR4 +import Testing + + +/// The civil-arithmetic effective-time kernel against the `Calendar`-based builders it replaces (oracle O5), +/// plus the behaviour each of them must keep. +@Suite +struct HealthKitEffectiveTimeTests { + /// SplitMix64, so a failing sweep replays exactly. + private struct SeededGenerator: RandomNumberGenerator { + var state: UInt64 + + mutating func next() -> UInt64 { + state &+= 0x9E37_79B9_7F4A_7C15 + var value = state + value = (value ^ (value >> 30)) &* 0xBF58_476D_1CE4_E5B9 + value = (value ^ (value >> 27)) &* 0x94D0_49BB_1331_11EB + return value ^ (value >> 31) + } + } + + /// Seeded instants per zone. `TEST_RUNNER_GROVE_EFFECTIVE_TIME_SWEEP=1000000` runs the full O5 sweep. + private static let sweepCount = ProcessInfo.processInfo.environment["GROVE_EFFECTIVE_TIME_SWEEP"].flatMap { Int($0) } ?? 3_000 + + /// Named zones with odd, LMT, non-hour and DST offsets, plus both ±18 h extremes. + private static let namedZones: [TimeZone] = [ + "America/Los_Angeles", "Asia/Kolkata", "Asia/Kathmandu", "America/St_Johns", "Europe/Amsterdam", + "Africa/Monrovia", "Australia/Lord_Howe", "Pacific/Chatham", "Pacific/Kiritimati" + ].compactMap { TimeZone(identifier: $0) } + [64_800, -64_800, 37].compactMap { TimeZone(secondsFromGMT: $0) } + + /// Twelve sweep zones: none (UTC) and every named or fixed zone above. + private static let zones: [TimeZone?] = [nil] + namedZones + + /// Ties, fractions, a repeated DST hour, the year 0 and 9999 boundaries, the 1582 reform, Foundation's + /// far-future clamp, and instants with no millisecond count. + private static let edges: [Date] = { + let instants: [TimeInterval] = [ + 0.0005, 0.0015, -0.0005, -0.0015, 0.9995, 1.0005, 1_787_148_600.251, 1_787_148_600.25, + 1_793_521_800, 1_793_525_400, 253_402_300_799, 253_402_300_799.9995, 253_402_300_800, 253_402_290_000, + -62_135_596_800, -62_135_596_801, -62_167_219_200, -62_200_000_000, -2_208_988_800, + 1e13, 1e15, 9.2e15, 1e21, -1e21, .nan, .infinity, -.infinity + ] + let aroundReform: [TimeInterval] = [0, 1, -1, 3_600, -3_600, 50_400, -50_400, 64_800, -64_800, 86_400, -86_400, 172_800] + return (instants + aroundReform.map { $0 - 12_219_292_800 }).map { Date(timeIntervalSince1970: $0) } + [.distantPast, .distantFuture] + }() + + /// A third each: years −90 through 10200, the decades around the 1582 reform, and 1970 through 2039; + /// a ±0.5 ms jitter puts exact and near half-millisecond ties in every range. + private static func sweepInstant(_ generator: inout SeededGenerator) -> Date { + let range: ClosedRange = switch generator.next() % 3 { + case 0: -65_000_000_000_000...260_000_000_000_000 + case 1: -13_000_000_000_000 ... -11_000_000_000_000 + default: 0...2_200_000_000_000 + } + let milliseconds = Int64.random(in: range, using: &generator) + let jitter = Double(Int.random(in: -500...500, using: &generator)) / 1_000_000 + return Date(timeIntervalSince1970: Double(milliseconds) / 1_000 + jitter) + } + + /// `nil` when both builders print the same date-time and extension, or throw the same failure. + private static func mobileMismatch(_ date: Date, zone: TimeZone?) -> String? { + let legacy = Result { try HealthKitConverter.effectiveDateTime(date, sourceTimeZone: zone) } + let kernel = Result { () throws(HealthKitValueFailure) in try HealthKitEffectiveTime.dateTime(date, zone: zone) } + switch (legacy, kernel) { + case let (.success(lhs), .success(rhs)) where lhs == rhs && lhs.value?.description == rhs.value?.description: + return nil + case let (.failure(lhs), .failure(rhs)) where lhs as? HealthKitValueFailure == rhs: + return nil + default: + return "\(date.timeIntervalSince1970) \(zone?.identifier ?? "none"): \(legacy) != \(kernel)" + } + } + + /// `nil` when both ECG builders yield the same date-time and lexeme, or throw the same error. + private static func ecgMismatch(_ date: Date, offset: Decimal, zone: TimeZone) -> String? { + let legacy = Result { try HealthKitConverter.exactHealthKitDateTime(date, offsetSeconds: offset, timeZone: zone) } + let kernel = Result { () throws(HealthKitConversionError) in + try HealthKitEffectiveTime.exactDateTime(date, offset: offset, zone: zone) + } + switch (legacy, kernel) { + case let (.success(lhs), .success(rhs)) where lhs == rhs && lhs.description == rhs.description: + return nil + case let (.failure(lhs), .failure(rhs)) where lhs as? HealthKitConversionError == rhs: + return nil + default: + return "\(date.timeIntervalSince1970)+\(offset) \(zone.identifier): \(legacy) != \(kernel)" + } + } + + @Test("Every sweep zone resolves") + func sweepZones() { + #expect(Self.zones.count == 13) + #expect(Self.namedZones.count == 12) + } + + @Test("Mobile instants equal the Calendar builder's over the seeded sweep and the edge list") + func mobileSweep() { + var generator = SeededGenerator(state: 0x4D32_4D6F_6269_6C65) + var mismatches: [String] = [] + for zone in Self.zones { + for date in Self.edges + (0..(_ legacy: Result, _ kernel: Result) -> Bool { + switch (legacy, kernel) { + case let (.success(lhs), .success(rhs)): + lhs == rhs && String(describing: lhs) == String(describing: rhs) + case let (.failure(lhs), .failure(rhs)): + lhs as? HealthKitValueFailure == rhs + default: + false + } + } + + @Test("A quantity template yields the builder's quantity or its error for every contract and value") + func quantitiesMatchTheBuilder() { + var mismatches: [String] = [] + let quantities = Self.contracts.flatMap { contract in + [contract.quantity].compactMap(\.self) + contract.components.compactMap(\.quantity) + } + for contract in quantities { + let template = QuantityTemplate(contract) + for value in Self.values { + let legacy = Result { try HealthKitConverter.fhirQuantity(value: value, contract: contract) } + let kernel = Result { () throws(HealthKitValueFailure) in try template.quantity(value) } + if !Self.agree(legacy, kernel) { + mismatches.append("\(contract.code) \(value): \(legacy) != \(kernel)") + } + } + } + #expect(!quantities.isEmpty) + #expect(mismatches.isEmpty, "\(mismatches)") + } + + @Test("A component template yields the workout statistic builder's component for every workout component") + func workoutComponentsMatchTheBuilder() throws { + let components = MeasurementCatalog.workout.components.filter { $0.quantity != nil } + #expect(!components.isEmpty) + for component in components { + let template = try #require(ComponentTemplate(component)) + for value in Self.values { + let legacy = Result { try HealthKitConverter.component(component.id, value: value) } + let kernel = Result { () throws(HealthKitValueFailure) in try template.component(value) } + #expect(Self.agree(legacy, kernel), "\(component.id) \(value)") + } + } + } + + /// The blood-pressure builder's coding, written out as it builds it, for every component with a quantity. + @Test("A component template's code is the contract's code and system, without a display") + func componentCodes() throws { + for component in Self.contracts.flatMap(\.components) { + guard let template = ComponentTemplate(component) else { + #expect(component.quantity == nil) + continue + } + let coding = Coding( + code: component.code.asFHIRStringPrimitive(), + system: FHIRPrimitive(FHIRURI(stringLiteral: component.system)) + ) + #expect(template.code == CodeableConcept(coding: [coding])) + } + } + + @Test("The template refuses a value outside the contract's domain") + func domainRefusal() throws { + let template = QuantityTemplate(try #require(MeasurementCatalog.oxygenSaturation.quantity)) + #expect(throws: HealthKitValueFailure.shapeInvalid) { + try template.quantity(101) + } + #expect(try template.quantity(98).value?.value?.decimal == 98) + } +} + +#endif From 993efcc495128e387d07e95ce4b51b14e449068f Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sat, 3 Oct 2026 18:17:49 +0200 Subject: [PATCH 051/220] State HealthKit Effective Times in the Proleptic Gregorian Calendar Owner decision D2 (synthesis section 20, approved): effective dateTimes follow ISO 8601 and FHIR, so dates before the 1582 reform are proleptic Gregorian and a local year outside 0001 through 9999 is refused. The legacy calendar fallback is gone. What changed: - HealthKitEffectiveTime drops its Foundation fallback (the 1582...9999 arithmetic window and foundationCivilTime). Every local time now goes through civil_from_days. civilTime refuses a local year outside 1...9999 for both builders: Mobile returns .shapeInvalid as before, ECG returns .ecgEvidence(.invalidSourcePeriod) as before. - Production now calls the kernel, because D2 cannot change output while the Calendar builders still produce it. Observation effective times call HealthKitEffectiveTime.dateTime/period. The four ECG sites call exactDateTime. HealthKitConverter.effectiveDateTime/effectivePeriod, HealthKitMobileCanonicalization.effectiveDateTime and HealthKitConverter.exactHealthKitDateTime are deleted. All were internal and are covered by M2's O5 equivalence. No Calendar is left in GroveHealthKitFHIR. - Tests: the O5 sweeps no longer compare against the deleted builders. They now check the kernel's fields against Foundation's Gregorian calendar, only where that calendar is proleptic (local 1582-10-15 through 9999) and where Mobile offsets are within the +/-14 h a FHIR lexeme states. With TEST_RUNNER_GROVE_EFFECTIVE_TIME_SWEEP=1000000 there are 0 mismatches across 13 zones. The sweep now draws and checks one instant at a time, each inside an autoreleasepool. The earlier version built a 10^6-element array per zone, and at 10^6 that growth failed graphValidationDrainsItsOwnTemporaries, which measures the process-wide live heap while other suites run. A pinned test replaces the Julian one: 1582-10-14T23:59:59Z, 1500-01-01, 0001-01-01, and year 0 refused for both builders. A +18 h zone is pinned as a Mobile refusal, as it always was: DateTime rejects the lexeme. Four test files call the kernel instead of the deleted functions. Output diff: only local times before 1582-10-15. - Before the reform, the date moves from Foundation's Julian date to the proleptic Gregorian date. Time, offset, fraction and the timezone extension are unchanged. Example: 1582-10-04T23:59:59Z becomes 1582-10-14T23:59:59Z. The shift is 10 days at the reform, 0 days from 200-03-01 through 300-02-28, and -2 days in year 1. - A local time in proleptic year 0 or earlier (before 0001-01-01) is now refused. Foundation printed its Julian date, which has an era-relative positive year before 1 AD. For example, -62135769600 printed as 0001-01-01T00:00:00Z; in proleptic dates it is 0000-12-30. - ECG instants with a local year above 9999 are now refused instead of being printed as 5-or-more-digit years that no FHIR dateTime admits. HealthKit cannot produce one: HKSample refuses an end date at or after 4001-01-01 (distantFuture). - Unchanged: every local time from 1582-10-15 on; all 42 goldens and outlines.json (lossless-token equal); every other test. How the diff was enumerated: a throwaway probe test (not committed) recorded 167,800 vectors before and after this change. They cover Mobile dateTime and ECG exactDateTime (offsets 0 and 0.25) in 8 zones (none, LA, Kolkata, Kathmandu, Amsterdam, Monrovia LMT, +/-18 h) over a 115-day grid from -65e9 s to 4.2e9 s, +/-2 days around the reform and year 1, BC instants, the 9999/10000 boundary, far-future values and non-finite values. It also recorded 8 end-to-end ECG and heart-rate conversions. Changed vectors, each classified by predicate, with 0 unclassified: Mobile: 4,705 pre-reform date shifts, 300 newly refused (year <= 0) ECG: 75,280 pre-reform date shifts, 4,802 newly refused (year <= 0), 106 newly refused (year > 9999, unreachable through HealthKit) End-to-end ECG graphs: 6 (1499-12-22 -> 1499-12-31 and 1582-10-04 -> 1582-10-14 in LA LMT; years 0003 and 0001 now refused) End-to-end heart-rate graphs: none (LA LMT before 1883 is not whole minutes and was refused before and after) In the UTC column, all 6,988 Mobile lexemes equal Python's proleptic datetime arithmetic. There is no content corpus in this branch yet (M0 has not landed), so no corpus file changes. Rebased onto 28f93119 (exchange-ledger fix round), which versions the bytes this adapter emits: HealthKitAssembly.outputRevision enters every exporter's context fingerprint and must be bumped whenever equal inputs can yield other bytes. This commit changes the bytes of local times before 1582-10-15 and refuses local years 0 and earlier and ECG years above 9999, so it bumps the revision from 2 to 3. No golden changes, so every GoldenOutputRevisionTests row stays. Co-Authored-By: Claude Opus 5.5 --- .../HealthKitAssembly.swift | 2 +- .../HealthKitConverter+ECG.swift | 64 --------- .../HealthKitConverter+ECGCore.swift | 22 ++-- .../HealthKitConverter+Observation.swift | 26 +--- .../HealthKitEffectiveTime.swift | 48 +++---- .../HealthKitMobileCanonicalization.swift | 92 ------------- .../HealthKitECGEvidenceValidatorTests.swift | 2 +- .../HealthKitEffectiveTimeTests.swift | 124 +++++++++++++----- ...HealthKitMobileCanonicalizationTests.swift | 21 +-- .../ProducerAlignmentTests.swift | 6 +- 10 files changed, 126 insertions(+), 281 deletions(-) diff --git a/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift b/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift index 75905b33f..f63a86134 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitAssembly.swift @@ -62,7 +62,7 @@ struct HealthKitAssembly: Sendable { /// The revision of the graphs this adapter's assembly builds. Bump it whenever the bytes it emits can /// change for equal inputs: it enters every exporter's context fingerprint, so an event reserved under an /// older revision is never redelivered under the same identifier with different bytes. - static let outputRevision: UInt = 2 + static let outputRevision: UInt = 3 static let adapter = ExchangeAdapterContract( adapterID: HealthKitConverter.adapterID, diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+ECG.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+ECG.swift index f36ba72e5..3a57ffabd 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+ECG.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter+ECG.swift @@ -115,70 +115,6 @@ extension HealthKitConverter { )) return observation } - - /// Constructs a FHIR dateTime from the shortest round-trip representation of - /// Foundation's source instant, then adds an exact decimal HealthKit offset. - /// Going through `Date.addingTimeInterval` would introduce a second binary - /// floating-point rounding step and can make SampledData's period arithmetic - /// fail despite a complete uniform voltage enumeration. - static func exactHealthKitDateTime( - _ date: Date, - offsetSeconds: Decimal = 0, - timeZone: TimeZone - ) throws -> DateTime { - let epochSeconds = date.timeIntervalSince1970 - guard epochSeconds.isFinite, - let epochDecimal = Decimal( - string: String(epochSeconds), - locale: Locale(identifier: "en_US_POSIX") - ) else { - throw HealthKitConversionError.ecgEvidence(.invalidSourcePeriod) - } - let target = epochDecimal + offsetSeconds - let approximateTarget = NSDecimalNumber(decimal: target).doubleValue - guard approximateTarget.isFinite, - approximateTarget >= Double(Int64.min), - approximateTarget <= Double(Int64.max) else { - throw HealthKitConversionError.ecgEvidence(.invalidSourcePeriod) - } - - var wholeSeconds = Int64(floor(approximateTarget)) - var fractionalSecond = target - Decimal(wholeSeconds) - if fractionalSecond < 0 { - wholeSeconds -= 1 - fractionalSecond += 1 - } else if fractionalSecond >= 1 { - wholeSeconds += 1 - fractionalSecond -= 1 - } - - let wholeSecondDate = Date(timeIntervalSince1970: TimeInterval(wholeSeconds)) - // A named zone would be serialized with the first occurrence's offset in a repeated DST hour. - let offsetZone = timeZone.fixedOffset(at: wholeSecondDate) - var calendar = Calendar(identifier: .gregorian) - calendar.timeZone = offsetZone - let components = calendar.dateComponents( - [.year, .month, .day, .hour, .minute, .second], - from: wholeSecondDate - ) - guard let year = components.year, - let month = components.month.flatMap(UInt8.init(exactly:)), - let day = components.day.flatMap(UInt8.init(exactly:)), - let hour = components.hour.flatMap(UInt8.init(exactly:)), - let minute = components.minute.flatMap(UInt8.init(exactly:)), - let second = components.second else { - throw HealthKitConversionError.ecgEvidence(.invalidSourcePeriod) - } - return DateTime( - date: FHIRDate(year: year, month: month, day: day), - time: FHIRTime( - hour: hour, - minute: minute, - second: Decimal(second) + fractionalSecond - ), - timezone: offsetZone - ) - } } #endif diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+ECGCore.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+ECGCore.swift index 7fd48390e..35a510e6c 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+ECGCore.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter+ECGCore.swift @@ -175,14 +175,8 @@ extension HealthKitConverter { Extension( url: Canonicals.healthKitECGSourcePeriodExtension, value: .period(Period( - end: FHIRPrimitive(try exactHealthKitDateTime( - source.endDate, - timeZone: source.timeZone - )), - start: FHIRPrimitive(try exactHealthKitDateTime( - source.startDate, - timeZone: source.timeZone - )) + end: FHIRPrimitive(try HealthKitEffectiveTime.exactDateTime(source.endDate, offset: 0, zone: source.timeZone)), + start: FHIRPrimitive(try HealthKitEffectiveTime.exactDateTime(source.startDate, offset: 0, zone: source.timeZone)) )) ) ] @@ -197,15 +191,15 @@ extension HealthKitConverter { throw HealthKitConversionError.ecgEvidence(.invalidSourcePeriod) } return Period( - end: FHIRPrimitive(try exactHealthKitDateTime( + end: FHIRPrimitive(try HealthKitEffectiveTime.exactDateTime( source.startDate, - offsetSeconds: waveform.lastOffsetSeconds, - timeZone: timeZone + offset: waveform.lastOffsetSeconds, + zone: timeZone )), - start: FHIRPrimitive(try exactHealthKitDateTime( + start: FHIRPrimitive(try HealthKitEffectiveTime.exactDateTime( source.startDate, - offsetSeconds: waveform.firstOffsetSeconds, - timeZone: timeZone + offset: waveform.firstOffsetSeconds, + zone: timeZone )) ) } diff --git a/Sources/GroveHealthKitFHIR/HealthKitConverter+Observation.swift b/Sources/GroveHealthKitFHIR/HealthKitConverter+Observation.swift index c05d04e01..ed3f12ca2 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitConverter+Observation.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitConverter+Observation.swift @@ -165,15 +165,15 @@ extension HealthKitConverter { case .dateTime, .dateTimeOrPeriod: // Scalar HealthKit samples stay point-in-time even when the shared profile also admits // a Period for a separately modeled aggregate such as ECG average heart rate. - observation.effective = .dateTime(try effectiveDateTime(sample.startDate, sourceTimeZone: sourceTimeZone)) + observation.effective = .dateTime(try HealthKitEffectiveTime.dateTime(sample.startDate, zone: sourceTimeZone)) case .period: guard admitsEffectivePeriod(start: sample.startDate, end: sample.endDate, contract: contract) else { throw HealthKitValueFailure.effectivePeriodInvalid } - observation.effective = .period(try effectivePeriod( + observation.effective = .period(try HealthKitEffectiveTime.period( start: sample.startDate, end: sample.endDate, - sourceTimeZone: sourceTimeZone + zone: sourceTimeZone )) } } @@ -188,26 +188,6 @@ extension HealthKitConverter { end > start || (end == start && !nonZeroPeriodMeasurements.contains(contract.id)) } - /// An effective instant in the source's own time zone, which also travels as the `timezone` - /// extension, or in UTC when the source names none. - static func effectiveDateTime(_ date: Date, sourceTimeZone: TimeZone?) throws -> FHIRPrimitive { - var dateTime = FHIRPrimitive(try HealthKitMobileCanonicalization.effectiveDateTime(date, timeZone: sourceTimeZone ?? .utc)) - if let sourceTimeZone { - dateTime.append( - extension: Extension(url: Canonicals.timezone, value: .code(sourceTimeZone.identifier.asFHIRStringPrimitive())), - behaviour: .replace - ) - } - return dateTime - } - - static func effectivePeriod(start: Date, end: Date, sourceTimeZone: TimeZone?) throws -> Period { - Period( - end: try effectiveDateTime(end, sourceTimeZone: sourceTimeZone), - start: try effectiveDateTime(start, sourceTimeZone: sourceTimeZone) - ) - } - private static func measurementDisplay(_ contract: HealthKitFHIRObservationContract) -> String { contract.code.display ?? measurementDisplays[contract.id, default: contract.id] } diff --git a/Sources/GroveHealthKitFHIR/HealthKitEffectiveTime.swift b/Sources/GroveHealthKitFHIR/HealthKitEffectiveTime.swift index 8bdabfddd..2db509296 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitEffectiveTime.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitEffectiveTime.swift @@ -46,9 +46,9 @@ enum EffectiveRule: Hashable, Sendable { /// They keep the source zone's offset at the unrounded instant, print `.mmm` untrimmed, and write a /// zero offset as `Z`. ECG timing instead keeps exact Decimal seconds (``exactDateTime(_:offset:zone:)``). /// -/// Local times outside 1582-10-15 through 9999 take Foundation's Gregorian calendar, which switches to -/// the Julian calendar before the 1582 reform and clamps far-future years, so those instants keep the -/// bytes they have always had. +/// Dates are proleptic Gregorian, as ISO 8601 and FHIR define them, also before the 1582 reform where +/// Foundation's Gregorian calendar switches to Julian dates. A local year outside 0001 through 9999 has +/// no FHIR date-time and is refused. @available(iOS 18, macOS 15, watchOS 11, *) enum HealthKitEffectiveTime { /// Wall-clock fields of one local second. @@ -61,9 +61,8 @@ enum HealthKitEffectiveTime { let second: Int } - /// Local seconds since 1970 from 1582-10-15T00:00 through 9999-12-31T23:59:59, where Foundation's - /// Gregorian calendar is proleptic Gregorian and `civil_from_days` agrees with it. - private static let arithmeticWindow: Swift.Range = -12_219_292_800 ..< 253_402_300_800 + /// The years a FHIR date-time can state. + private static let statableYears: ClosedRange = 1...9_999 /// The widest UTC offset Foundation represents, ±18 hours. private static let maximumOffsetSeconds = 64_800 @@ -117,7 +116,7 @@ enum HealthKitEffectiveTime { let wholeSecondDate = Date(timeIntervalSince1970: TimeInterval(wholeSeconds)) let fixedZone = zone.fixedOffset(at: wholeSecondDate) let fixedOffset = fixedZone.secondsFromGMT(for: wholeSecondDate) - guard let civil = civilTime(seconds: wholeSeconds, offset: fixedOffset, zone: fixedZone), + guard let civil = civilTime(seconds: wholeSeconds, offset: fixedOffset), let month = UInt8(exactly: civil.month), let day = UInt8(exactly: civil.day), let hour = UInt8(exactly: civil.hour), @@ -133,7 +132,7 @@ enum HealthKitEffectiveTime { /// The Mobile lexeme `YYYY-MM-DDThh:mm:ss[.mmm](Z|±hh:mm)`, or `nil` when the instant has none: /// non-finite, beyond Int64 milliseconds, an offset that is not whole minutes within ±18 h, or a - /// local year outside 0…9999. + /// local year outside 1…9999. private static func mobileLexeme(_ date: Date, zone: TimeZone?) -> String? { guard let milliseconds = Int64(exactly: (date.timeIntervalSince1970 * 1_000).rounded(.toNearestOrEven)) else { return nil @@ -143,7 +142,7 @@ enum HealthKitEffectiveTime { return nil } let (wholeSeconds, millisecond) = ExchangeInstant.floorDivide(milliseconds, by: 1_000) - guard let civil = civilTime(seconds: wholeSeconds, offset: offset), (0...9_999).contains(civil.year) else { + guard let civil = civilTime(seconds: wholeSeconds, offset: offset) else { return nil } var lexeme = ExchangeInstant.padded(Int64(civil.year), width: 4) @@ -164,17 +163,20 @@ enum HealthKitEffectiveTime { ExchangeInstant.padded(Int64(value), width: 2) } - /// The wall-clock fields of a UTC second count at `offset` seconds from UTC; `zone`, when given, is the - /// zone stating that offset, else the fixed-offset zone of `offset`. - private static func civilTime(seconds: Int64, offset: Int, zone: TimeZone? = nil) -> CivilTime? { + /// The proleptic Gregorian wall-clock fields of a UTC second count at `offset` seconds from UTC, or + /// `nil` when the local year is not statable. + private static func civilTime(seconds: Int64, offset: Int) -> CivilTime? { let (local, overflow) = seconds.addingReportingOverflow(Int64(offset)) - guard !overflow, arithmeticWindow.contains(local) else { - return (zone ?? TimeZone(secondsFromGMT: offset)).flatMap { foundationCivilTime(seconds: seconds, zone: $0) } + guard !overflow else { + return nil } let (days, secondOfDay) = ExchangeInstant.floorDivide(local, by: 86_400) let date = ExchangeInstant.civilDate(fromDays: days) + guard let year = Int(exactly: date.year), statableYears.contains(year) else { + return nil + } return CivilTime( - year: Int(date.year), + year: year, month: Int(date.month), day: Int(date.day), hour: Int(secondOfDay / 3_600), @@ -182,22 +184,6 @@ enum HealthKitEffectiveTime { second: Int(secondOfDay % 60) ) } - - /// The fields Foundation's Gregorian calendar states for a UTC second count in `zone`, including its Julian - /// dates before the reform, its era-relative years before year 1 and its clamp of far-future instants. - private static func foundationCivilTime(seconds: Int64, zone: TimeZone) -> CivilTime? { - var calendar = Calendar(identifier: .gregorian) - calendar.timeZone = zone - let parts = calendar.dateComponents( - [.year, .month, .day, .hour, .minute, .second], - from: Date(timeIntervalSince1970: TimeInterval(seconds)) - ) - guard let year = parts.year, let month = parts.month, let day = parts.day, - let hour = parts.hour, let minute = parts.minute, let second = parts.second else { - return nil - } - return CivilTime(year: year, month: month, day: day, hour: hour, minute: minute, second: second) - } } #endif diff --git a/Sources/GroveHealthKitFHIR/HealthKitMobileCanonicalization.swift b/Sources/GroveHealthKitFHIR/HealthKitMobileCanonicalization.swift index 5548f526a..7441a7236 100644 --- a/Sources/GroveHealthKitFHIR/HealthKitMobileCanonicalization.swift +++ b/Sources/GroveHealthKitFHIR/HealthKitMobileCanonicalization.swift @@ -30,98 +30,6 @@ enum HealthKitMobileCanonicalization { static func scalarDecimal(_ value: Double) throws -> FHIRPrimitive { FHIRPrimitive(FHIRDecimal(try scalarDecimalValue(value))) } - - /// Rounds one Foundation `Date` to the nearest millisecond, ties to even, while retaining - /// the source timezone's offset representation at the unrounded instant. - static func effectiveDateTime(_ date: Date, timeZone: TimeZone) throws -> DateTime { - let totalMilliseconds = try roundedMilliseconds(sinceEpoch: date) - var wholeSeconds = totalMilliseconds / 1_000 - var millisecond = totalMilliseconds % 1_000 - if millisecond < 0 { - wholeSeconds -= 1 - millisecond += 1_000 - } - - let sourceOffset = timeZone.secondsFromGMT(for: date) - guard sourceOffset.isMultiple(of: 60), - let fixedOffset = TimeZone(secondsFromGMT: sourceOffset) else { - throw HealthKitValueFailure.shapeInvalid - } - let lexical = try lexicalDateTime( - wholeSeconds: wholeSeconds, - millisecond: millisecond, - sourceOffset: sourceOffset, - fixedOffset: fixedOffset - ) - do { - return try DateTime(lexical) - } catch { - throw HealthKitValueFailure.shapeInvalid - } - } - - private static func roundedMilliseconds(sinceEpoch date: Date) throws -> Int64 { - let milliseconds = (date.timeIntervalSince1970 * 1_000).rounded(.toNearestOrEven) - guard milliseconds.isFinite, - let result = Int64(exactly: milliseconds) else { - throw HealthKitValueFailure.shapeInvalid - } - return result - } - - private static func lexicalDateTime( - wholeSeconds: Int64, - millisecond: Int64, - sourceOffset: Int, - fixedOffset: TimeZone - ) throws -> String { - var calendar = Calendar(identifier: .gregorian) - calendar.locale = Locale(identifier: "en_US_POSIX") - calendar.timeZone = fixedOffset - let components = calendar.dateComponents( - [.year, .month, .day, .hour, .minute, .second], - from: Date(timeIntervalSince1970: TimeInterval(wholeSeconds)) - ) - guard let year = components.year, - (0...9_999).contains(year), - let month = components.month, - let day = components.day, - let hour = components.hour, - let minute = components.minute, - let second = components.second else { - throw HealthKitValueFailure.shapeInvalid - } - - let fraction = millisecond == 0 - ? "" - : String(format: ".%03lld", locale: Locale(identifier: "en_US_POSIX"), millisecond) - let offset: String - if sourceOffset == 0 { - offset = "Z" - } else { - let magnitude = abs(sourceOffset) - offset = String( - format: "%@%02d:%02d", - locale: Locale(identifier: "en_US_POSIX"), - sourceOffset < 0 ? "-" : "+", - magnitude / 3_600, - magnitude % 3_600 / 60 - ) - } - let lexical = String( - format: "%04d-%02d-%02dT%02d:%02d:%02d%@%@", - locale: Locale(identifier: "en_US_POSIX"), - year, - month, - day, - hour, - minute, - second, - fraction, - offset - ) - return lexical - } } #endif diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitECGEvidenceValidatorTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitECGEvidenceValidatorTests.swift index ca36fcdd4..2541f0cee 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitECGEvidenceValidatorTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitECGEvidenceValidatorTests.swift @@ -409,7 +409,7 @@ struct HealthKitECGEvidenceValidatorTests { func ecgTimestampsInTheRepeatedDSTHourKeepTheirInstant(_ zoneName: String, _ instantText: String) throws { let zone = try #require(TimeZone(identifier: zoneName)) let instant = try #require(ISO8601DateFormatter().date(from: instantText)) - let dateTime = try HealthKitConverter.exactHealthKitDateTime(instant, offsetSeconds: 0.25, timeZone: zone) + let dateTime = try HealthKitEffectiveTime.exactDateTime(instant, offset: 0.25, zone: zone) let decoded = try JSONDecoder().decode(DateTime.self, from: JSONEncoder().encode(dateTime)) #expect(try decoded.asNSDate() == instant.addingTimeInterval(0.25)) } diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitEffectiveTimeTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitEffectiveTimeTests.swift index c3f2ac657..ab45562a3 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitEffectiveTimeTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitEffectiveTimeTests.swift @@ -15,8 +15,8 @@ import ModelsR4 import Testing -/// The civil-arithmetic effective-time kernel against the `Calendar`-based builders it replaces (oracle O5), -/// plus the behaviour each of them must keep. +/// The civil-arithmetic effective-time kernel against Foundation's Gregorian calendar where that calendar is +/// proleptic, its proleptic dates before the 1582 reform, and the behaviour each builder keeps. @Suite struct HealthKitEffectiveTimeTests { /// SplitMix64, so a failing sweep replays exactly. @@ -32,7 +32,8 @@ struct HealthKitEffectiveTimeTests { } } - /// Seeded instants per zone. `TEST_RUNNER_GROVE_EFFECTIVE_TIME_SWEEP=1000000` runs the full O5 sweep. + /// Seeded instants per zone; `TEST_RUNNER_GROVE_EFFECTIVE_TIME_SWEEP=1000000` runs a million. They are drawn and + /// checked one at a time, each in its own pool, so a large sweep does not grow the heap concurrent suites measure. private static let sweepCount = ProcessInfo.processInfo.environment["GROVE_EFFECTIVE_TIME_SWEEP"].flatMap { Int($0) } ?? 3_000 /// Named zones with odd, LMT, non-hour and DST offsets, plus both ±18 h extremes. @@ -57,6 +58,10 @@ struct HealthKitEffectiveTimeTests { return (instants + aroundReform.map { $0 - 12_219_292_800 }).map { Date(timeIntervalSince1970: $0) } + [.distantPast, .distantFuture] }() + /// Local seconds since 1970 from 1582-10-15T00:00 through 9999-12-31T23:59:59: the only local times at which + /// Foundation's Gregorian calendar is proleptic Gregorian, so the only ones it can check the kernel at. + private static let foundationWindow: Swift.Range = -12_219_292_800 ..< 253_402_300_800 + /// A third each: years −90 through 10200, the decades around the 1582 reform, and 1970 through 2039; /// a ±0.5 ms jitter puts exact and near half-millisecond ties in every range. private static func sweepInstant(_ generator: inout SeededGenerator) -> Date { @@ -70,34 +75,66 @@ struct HealthKitEffectiveTimeTests { return Date(timeIntervalSince1970: Double(milliseconds) / 1_000 + jitter) } - /// `nil` when both builders print the same date-time and extension, or throw the same failure. + /// Foundation's `[year, month, day, hour, minute, second, offset]` for a whole UTC second at a fixed offset, + /// or none when the local time lies outside ``foundationWindow``. + private static func foundationFields(seconds: Int64, offset: Int) -> [Int] { + guard foundationWindow.contains(seconds + Int64(offset)), let zone = TimeZone(secondsFromGMT: offset) else { + return [] + } + var calendar = Calendar(identifier: .gregorian) + calendar.timeZone = zone + let parts = calendar.dateComponents( + [.year, .month, .day, .hour, .minute, .second], + from: Date(timeIntervalSince1970: TimeInterval(seconds)) + ) + return [parts.year, parts.month, parts.day, parts.hour, parts.minute, parts.second].compactMap(\.self) + [offset] + } + + /// The same fields of a built date-time, its seconds truncated to the whole second, or none without one. + private static func fields(_ dateTime: DateTime?) -> [Int] { + guard let dateTime, let time = dateTime.time, let zone = dateTime.timeZone else { + return [] + } + // `NSDecimalNumber.intValue` misreads long mantissas, so the seconds are rounded as a Decimal first. + var second = time.second + var wholeSecond = Decimal() + NSDecimalRound(&wholeSecond, &second, 0, .down) + let date = dateTime.date + return [date.year, Int(date.month ?? 0), Int(date.day ?? 0), Int(time.hour), Int(time.minute)] + + [NSDecimalNumber(decimal: wholeSecond).intValue, zone.secondsFromGMT()] + } + + /// `nil` when a Mobile instant whose local time Foundation can check has Foundation's fields; refusals, among + /// them offsets beyond the ±14 h a FHIR date-time states, and pre-reform dates are pinned separately. private static func mobileMismatch(_ date: Date, zone: TimeZone?) -> String? { - let legacy = Result { try HealthKitConverter.effectiveDateTime(date, sourceTimeZone: zone) } - let kernel = Result { () throws(HealthKitValueFailure) in try HealthKitEffectiveTime.dateTime(date, zone: zone) } - switch (legacy, kernel) { - case let (.success(lhs), .success(rhs)) where lhs == rhs && lhs.value?.description == rhs.value?.description: + let offset = zone?.secondsFromGMT(for: date) ?? 0 + guard let milliseconds = Int64(exactly: (date.timeIntervalSince1970 * 1_000).rounded(.toNearestOrEven)), + offset.isMultiple(of: 60), + abs(offset) <= 50_400 else { return nil - case let (.failure(lhs), .failure(rhs)) where lhs as? HealthKitValueFailure == rhs: + } + let expected = foundationFields(seconds: ExchangeInstant.floorDivide(milliseconds, by: 1_000).quotient, offset: offset) + guard !expected.isEmpty else { return nil - default: - return "\(date.timeIntervalSince1970) \(zone?.identifier ?? "none"): \(legacy) != \(kernel)" } + let actual = fields((try? HealthKitEffectiveTime.dateTime(date, zone: zone))?.value) + return actual == expected ? nil : "\(date.timeIntervalSince1970) \(zone?.identifier ?? "none"): \(actual) != \(expected)" } - /// `nil` when both ECG builders yield the same date-time and lexeme, or throw the same error. - private static func ecgMismatch(_ date: Date, offset: Decimal, zone: TimeZone) -> String? { - let legacy = Result { try HealthKitConverter.exactHealthKitDateTime(date, offsetSeconds: offset, timeZone: zone) } - let kernel = Result { () throws(HealthKitConversionError) in - try HealthKitEffectiveTime.exactDateTime(date, offset: offset, zone: zone) - } - switch (legacy, kernel) { - case let (.success(lhs), .success(rhs)) where lhs == rhs && lhs.description == rhs.description: + /// `nil` when an ECG instant a whole number of seconds after `date` has Foundation's fields at the zone's + /// fixed offset, wherever Foundation can check it. + private static func ecgMismatch(_ date: Date, offset: Int, zone: TimeZone) -> String? { + guard let since1970 = Int64(exactly: date.timeIntervalSince1970.rounded(.down)) else { return nil - case let (.failure(lhs), .failure(rhs)) where lhs as? HealthKitConversionError == rhs: + } + let wholeSeconds = since1970 + Int64(offset) + let zoneOffset = zone.secondsFromGMT(for: Date(timeIntervalSince1970: TimeInterval(wholeSeconds))) + let expected = foundationFields(seconds: wholeSeconds, offset: zoneOffset) + guard !expected.isEmpty else { return nil - default: - return "\(date.timeIntervalSince1970)+\(offset) \(zone.identifier): \(legacy) != \(kernel)" } + let actual = fields(try? HealthKitEffectiveTime.exactDateTime(date, offset: Decimal(offset), zone: zone)) + return actual == expected ? nil : "\(date.timeIntervalSince1970)+\(offset) \(zone.identifier): \(actual) != \(expected)" } @Test("Every sweep zone resolves") @@ -106,13 +143,14 @@ struct HealthKitEffectiveTimeTests { #expect(Self.namedZones.count == 12) } - @Test("Mobile instants equal the Calendar builder's over the seeded sweep and the edge list") + @Test("Mobile instants have Foundation's fields over the seeded sweep and the edge list") func mobileSweep() { var generator = SeededGenerator(state: 0x4D32_4D6F_6269_6C65) var mismatches: [String] = [] for zone in Self.zones { - for date in Self.edges + (0.. Date: Sat, 3 Oct 2026 20:34:29 +0200 Subject: [PATCH 052/220] Freeze the HealthKit Content Oracle Before the Rewrite Step 7 milestone M0 (synthesis section 15 M0, section 16 O2 and O6): the output oracle the content rewrite is measured against, recorded from the current builders (after a40ba177 and 60dc8824). Tests only; no Sources change. Content corpus (O2): - Tests/GroveHealthKitFHIRTests/Resources/ContentCorpus/content-corpus.jsonl, 3,003 lines, 3,993,971 bytes (sha256 4713acef...). One compact JSON object per vector: a stable "id", the "input" as data (ContentCorpusInput), and the "output" in full text: per graph the output resources (Observation, DocumentReference) exactly as the wire bytes carry them plus the rendered warnings; a refusal as registry code, location and Swift error; a policy omission; retraction targets; or a catalog projection. - Inputs are rebuilt through StoredSampleFixtures, which gains restated(_: shape:) (writes interval, device, metadata, UUID and writer over a built sample), electrocardiogram(shape:reading:) via StoredElectrocardiogram (an HKElectrocardiogram subclass stating its reading, which HealthKit keeps in C++ storage key-value coding cannot reach), voltageMeasurement, and internal allocate/write. Facts HealthKit refuses at creation (out-of-range category raws, quantities outside a type's range or minimum duration, reversed intervals, mistyped metadata, instants after 4000, unknown workout activities, State of Mind kinds and labels, incomplete blood-pressure pairs) are written onto bare or built instances. - Coverage, per family (graphs / refusals): quantity 1,176 (every one of the 120 quantity rows at a value its domain admits and at 0, 1.5, -1, 1e-7, 1e21, NaN, +-inf; the 8 percent rows also at 0.07, 0.14, 0.28, 0.282, 0.29, 0.55-0.58, 0.98, 0.5, 1; 747/429); category 690 (all 69 category rows at raw -1 through 8; 252/438); time 132 (body mass, heart rate, dietary energy, step count: start == end, +45 s, reversed; zones none, invalid, mistyped, LA, Kolkata, Kathmandu, St Johns, UTC; both occurrences of a repeated DST hour, LA LMT in 1800, .250, exact half-millisecond ties, years 9999/10000, 1500, years 1/0; 95/37); correlation 20 (blood-pressure members missing, extra, out of range, member zones, manual entry, foreign and sync keys; food); workout 116 (activity raws 0-90, 3000, 9999 with every distance type, each statistic, partial heart-rate readings, durations); State of Mind 27; assessment 10; bare rows 3 (audiogram, vision prescription, medication dose event); metadata 63 (motion context, insulin reason, cycle start, protection: valid, out of range, mistyped, absent; manual entry; sync pair variants with and without a writer; keys a path does not read; device with and without a unit token); precedence 19 (two faults at once); electrocardiogram 57 (every classification and symptoms status incl. unknown raws, algorithm versions, average heart rate nil/finite/ NaN, sampling frequency, every waveform refusal, zones, symptom relationships, links, sample entry); heartbeat series 8; workout route 6; CDA 6; clinical 20 (9 types, DSTU2, unknown release, refused payloads, no resource, links); retraction 218 (every row); catalog 220 (every row's entry, outputs and field dispositions; unit bindings; both unit lookups for 53 spellings); reverse projection 212 (a minimal Observation per generated measurement and BMI, and 16 edges: Period, missing parts, unit mismatch, manual entry, zones, 1500, sync identity, amendment, blood-pressure components). - ContentCorpusGrid generates every vector from the public catalog and generated contracts. With TEST_RUNNER_GROVE_GOLDEN_OUTPUT_DIR set the suite records each vector twice, requires identical tokens, and writes the corpus there (outside the checkout), like the goldens. - ContentCorpusTests reproduces every line in 8 parallel shards by lossless-token equality (first differing path on failure), checks that the grid states exactly the checked-in ids and inputs, and on every converted vector checks that each emitted output is one HealthKitCatalog .outputs(for:) names, with the primary output first (O6). Invariants (ContentInvariantTests, O6 as today's code states them): rule-table totality (supported rows without outputs are exactly food, audiogram and 5 characteristics; only the 12 platform-exclusive document rows mint outputs otherwise); unit compatibility (107 unit-bound quantity rows, the 108 unit-read bindings less BMI whose contract is not generated yet; both unit lookups of every binding); reverse map = inverse of the forward bindings (today's internal HealthKitSampleProjection map); every sample row has a conversion vector. Determinism is the corpus reproducing in other processes; Mobile milliseconds from 1970 stays pinned by HealthKitEffectiveTimeTests. compileDefects has no counterpart until M3 compiles plans. Deviations from the design: - No workout segment vectors: since 2569b5c4 a workout exports its session alone. - No reverse projection of converted Observations: healthKitSample() builds samples through HealthKit initializers, which raise an uncatchable exception for instants after 4000 and for types with a minimum duration (for example environmental audio exposure at start == end); the reverse/ vectors project curated Observations HealthKit accepts instead. - No duplicate blood-pressure members: today's member lookup walks a Set, whose order differs per process, so that output is not pinnable. - Inputs are read with Foundation's JSONDecoder, not LosslessJSONValue, whose string parser drops a leading U+FEFF (String(bytes:encoding:) strips a byte order mark). Also: TokenDiff becomes internal for the corpus; the M2 review finding is fixed (HealthKitEffectiveTimeTests says thirteen sweep zones, and names the 37-second offset). Output: unchanged; no file under Sources/ changed. Gate 1 (macOS): 682 test runs passed, 0 failed, 3 skipped (corpus regeneration and the two benchmark tests); all 42 goldens and outlines.json pass. SwiftLint strict and reuse lint clean. Release baseline (ConversionThroughputBenchmark, xcodebuild Release, ENABLE_TESTABILITY, N=5000, 3 runs, macOS 27.0, 18 cores, load average about 6), best convert / median convert / observation-content, us per sample: heartRate-minimal 952.5 / 1001.5 / 7.0 heartRate-deployment-watch 1255.4 / 1257.8 / 8.0 heartRate-deployment-recordingDevice 1568.4 / 1646.5 / 9.1 stepCount-minimal 969.2 / 981.1 / 11.0 stepCount-deployment 1205.3 / 1207.6 / 11.1 workout-noEvents-deployment 1297.5 / 1305.2 / 35.4 workout12segments-deployment 1295.5 / 1299.1 / 39.7 concurrent heartRate-deployment-watch, 1/2/4/6/8 threads: 806 / 1434 / 2372 / 2686 / 2466 conversions per second. A first run under heavy load from other builds (load average 36-140) was discarded. The harness's own check that graph.json is plain JSONEncoder output fails in all 7 scenarios, as it does at 60dc8824: the graph stores sorted, unescaped bytes (6,797 vs 7,037 for heartRate- minimal); porting the harness is M5's. Rebased onto 28f93119 (exchange-ledger fix round), whose writer default is now .omit: the three corpus vectors that convert a sample of a foreign writer (metadata/sync/pair, metadata/sync/version-zero and metadata/sync/version-integral-double) keep their recorded lines here, which still state the writer. The corpus restatement at the end of the branch regenerates them, so until that commit ContentCorpusTests and ContentCorpusExporterTests fail on exactly these three vectors. Co-Authored-By: Claude Opus 5.5 --- .../ContentCorpus/ContentCorpusCatalog.swift | 82 + .../ContentCorpusGrid+Catalog.swift | 174 + .../ContentCorpusGrid+Clinical.swift | 70 + .../ContentCorpusGrid+Metadata.swift | 212 ++ .../ContentCorpusGrid+Recordings.swift | 238 ++ .../ContentCorpusGrid+Records.swift | 194 ++ .../ContentCorpus/ContentCorpusGrid.swift | 199 ++ .../ContentCorpus/ContentCorpusInput.swift | 216 ++ .../ContentCorpus/ContentCorpusRecorder.swift | 202 ++ .../ContentCorpusSamples+Records.swift | 252 ++ .../ContentCorpus/ContentCorpusSamples.swift | 200 ++ .../ContentCorpus/ContentCorpusStore.swift | 189 ++ .../ContentCorpus/ContentCorpusTests.swift | 102 + .../ContentCorpus/ContentInvariantTests.swift | 181 + .../GoldenGraphTests.swift | 2 +- .../HealthKitEffectiveTimeTests.swift | 4 +- .../ContentCorpus/content-corpus.jsonl | 3003 +++++++++++++++++ .../StoredSampleFixtures.swift | 110 +- 18 files changed, 5614 insertions(+), 16 deletions(-) create mode 100644 Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusCatalog.swift create mode 100644 Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Catalog.swift create mode 100644 Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Clinical.swift create mode 100644 Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Metadata.swift create mode 100644 Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Recordings.swift create mode 100644 Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Records.swift create mode 100644 Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid.swift create mode 100644 Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusInput.swift create mode 100644 Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusRecorder.swift create mode 100644 Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusSamples+Records.swift create mode 100644 Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusSamples.swift create mode 100644 Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusStore.swift create mode 100644 Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusTests.swift create mode 100644 Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentInvariantTests.swift create mode 100644 Tests/GroveHealthKitFHIRTests/Resources/ContentCorpus/content-corpus.jsonl diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusCatalog.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusCatalog.swift new file mode 100644 index 000000000..2353dd3f4 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusCatalog.swift @@ -0,0 +1,82 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +@testable import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit +import ModelsR4 + + +/// Renders the public catalog surface the content layer publishes: inventory rows with their outputs and field +/// dispositions, the unit bindings and both unit lookups, and the reverse projection of Observations. +enum ContentCorpusCatalog { + static func projection(_ projection: ContentCorpusProjection) throws -> LosslessJSONValue { + switch projection { + case .entry(let type): + try entry(type) + case .unitBindings: + .array(HealthKitCatalog.unitBindings.map { binding in + .object([ + "ucumCode": .string(binding.ucumCode), + "displayUnit": .string(binding.displayUnit), + "unit": .string(binding.unit.unitString) + ]) + }) + case .unitSpellings(let spellings): + .object(Dictionary(spellings.map { spelling in + (spelling, LosslessJSONValue.object([ + "ucumCode": unitText(HealthKitCatalog.unit(forUCUMCode: spelling)), + "unitSpelling": unitText(HealthKitCatalog.unit(forUnitSpelling: spelling)) + ])) + }) { first, _ in first }) + case .reverse(let observation): + ContentCorpusRecorder.reverse(try JSONDecoder().decode(Observation.self, from: Data(observation.utf8))) + } + } + + /// One inventory row, the outputs its conversion mints, and what happens to each of its source fields. + private static func entry(_ type: String) throws -> LosslessJSONValue { + guard let sourceType = HealthKitSourceType(rawValue: type) else { + throw ContentCorpusSamples.RebuildError.unknownType(type) + } + let entry = HealthKitCatalog[sourceType] + return .object([ + "title": .string(entry.title), + "status": .string(entry.implementationStatus.rawValue), + "requirement": entry.requirement.map(LosslessJSONValue.string) ?? .null, + "measurements": .array(entry.measurements.map { measurement in + .object(["id": .string(measurement.id), "profiles": .array(measurement.profiles.map { .string(canonicalText($0)) })]) + }), + "outputs": .array(HealthKitCatalog.outputs(for: sourceType).map { output in + .object([ + "role": .string(output.role), + "discriminator": .string(output.discriminator), + "resourceType": .string(output.resourceType.rawValue), + "retractionRole": .string(output.retractionRole.rawValue) + ]) + }), + "fieldDispositions": .object((HealthKitCatalog.fieldDispositions[sourceType] ?? [:]).mapValues { .string($0.rawValue) }) + ]) + } + + private static func unitText(_ unit: HKUnit?) -> LosslessJSONValue { + unit.map { .string($0.unitString) } ?? .null + } + + private static func canonicalText(_ canonical: FHIRPrimitive) -> String { + guard let value = canonical.value else { + return "" + } + return [value.url.absoluteString, value.version].compactMap(\.self).joined(separator: "|") + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Catalog.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Catalog.swift new file mode 100644 index 000000000..83c5104a1 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Catalog.swift @@ -0,0 +1,174 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +@testable import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit + + +/// Clinical documents, retractions, the catalog projections and reverse projections. +extension ContentCorpusGrid { + /// CDA documents and clinical records: every type and admitted release, refused releases and payloads, + /// missing payloads, bytes kept as delivered, and every link. watchOS has neither. + static var clinicalDocuments: [ContentCorpusVector] { + #if os(watchOS) + [] + #else + cdaDocuments + clinicalRecords + #endif + } + + /// The deletion of a record of every inventory row. + static var retractions: [ContentCorpusVector] { + HealthKitContract.rows.map { row in + ContentCorpusVector(id: "retraction/\(row.sourceTypeIdentifier)", input: .retract(type: row.sourceTypeIdentifier)) + } + } + + /// Every inventory row with its outputs and field dispositions, the unit bindings, and both unit lookups for + /// every spelling the bindings use plus spellings they do not. + static var catalog: [ContentCorpusVector] { + let entries = HealthKitContract.rows.map { row in + ContentCorpusVector(id: "catalog/entry/\(row.sourceTypeIdentifier)", input: .catalog(projection: .entry(type: row.sourceTypeIdentifier))) + } + let spellings = Set(HealthKitCatalog.unitBindings.flatMap { [$0.ucumCode, $0.displayUnit] }) + .union(["", "%", "/h", "Cel", "kg", "kg/m2", "mmHg", "mm[Hg]", "beats/minute", "not-a-unit"]) + .sorted() + return entries + [ + ContentCorpusVector(id: "catalog/unit-bindings", input: .catalog(projection: .unitBindings)), + ContentCorpusVector(id: "catalog/unit-spellings", input: .catalog(projection: .unitSpellings(spellings: spellings))) + ] + } + + /// A minimal Observation of every generated measurement and of body-mass index, and the edges of the + /// reverse projection: Period and missing effective times, missing and mismatched values, manual entry, + /// zones, a pre-1582 date, sync identity and amendment, and blood-pressure components. + static var reverseProjections: [ContentCorpusVector] { + var observations = (MeasurementCatalog.all + HealthKitMeasurementCatalog.all).map { contract in + (contract.id, minimalObservation(contract)) + } + observations.append(("body-mass-index", observation(code: ("http://loinc.org", "39156-5"), quantity: quantity("kg/m2", unit: "kg/m2", value: 1)))) + let projected = observations.map { id, resource in + ContentCorpusVector(id: "reverse/\(id)", input: .catalog(projection: .reverse(observation: json(resource)))) + } + return projected + reverseEdges.map { label, resource in + ContentCorpusVector(id: "reverse/edge/\(label)", input: .catalog(projection: .reverse(observation: json(resource)))) + } + } + + /// Heart-rate Observations that each change one thing the reverse projection reads. + static var reverseEdges: [(String, [String: Any])] { + let heartRate = minimalObservation(MeasurementCatalog.heartRate, value: 72) + func changed(_ change: (inout [String: Any]) -> Void) -> [String: Any] { + var resource = heartRate + change(&resource) + return resource + } + let roleCoding = ["system": Canonicals.identifierRoleCodeSystem.value?.url.absoluteString ?? "", "code": "source-output"] + let sourceOutput: [String: Any] = ["system": "https://example.org/source-output", "value": "output-1", "type": ["coding": [roleCoding]]] + let manualEntry: [String: Any] = [ + "url": Canonicals.recordingMethod.value?.url.absoluteString ?? "", + "valueCoding": ["system": Canonicals.recordingMethodCodeSystem.value?.url.absoluteString ?? "", "code": "manual-entry"] + ] + let writerVersion: [String: Any] = ["url": Canonicals.writerRecordVersion.value?.url.absoluteString ?? "", "valueString": "5"] + return [ + ("period", changed { resource in + resource["effectiveDateTime"] = nil + resource["effectivePeriod"] = ["start": "2026-08-17T15:30:00-07:00", "end": "2026-08-17T15:30:45-07:00"] + }), + ("no-effective", changed { $0["effectiveDateTime"] = nil }), + ("no-value", changed { $0["valueQuantity"] = nil }), + ("unit-code-mismatch", changed { $0["valueQuantity"] = quantity("/s", unit: "beats/second", value: 1.2) }), + ("unit-system-mismatch", changed { $0["valueQuantity"] = quantity("/min", unit: "beats/minute", value: 72, system: "https://example.org/units") }), + ("unknown-code", changed { $0["code"] = ["coding": [["system": "http://loinc.org", "code": "0000-0"]]] }), + ("decimal-value", changed { $0["valueQuantity"] = quantity("/min", unit: "beats/minute", value: 72.5) }), + ("utc", changed { $0["effectiveDateTime"] = "2026-08-17T22:30:00Z" }), + ("fraction", changed { $0["effectiveDateTime"] = "2026-08-17T22:30:00.250Z" }), + ("date-only", changed { $0["effectiveDateTime"] = "2026-08-17" }), + ("pre-reform", changed { $0["effectiveDateTime"] = "1500-01-01T00:00:00Z" }), + ("manual-entry", changed { $0["extension"] = [manualEntry] }), + ("sync-identity", changed { resource in + resource["identifier"] = [sourceOutput] + resource["extension"] = [writerVersion] + }), + ("amended-sync-identity", changed { resource in + resource["identifier"] = [sourceOutput] + resource["status"] = "amended" + }), + ("blood-pressure-missing-diastolic", bloodPressure(diastolic: false)), + ("blood-pressure-unit-mismatch", bloodPressure(diastolic: true, unit: "kPa")) + ] + } + + /// The smallest Observation of `contract` the reverse projection reads: its code, a zoned instant (a minute's + /// Period for a Period measurement, as Grove emits it), and a value inside its domain in its unit (or a unitless + /// one when it has none), or the components of a panel. + static func minimalObservation(_ contract: MeasurementContract, value: Double? = nil) -> [String: Any] { + guard contract.id != MeasurementCatalog.bloodPressure.id else { + return bloodPressure(diastolic: true) + } + let unit = contract.quantity ?? QuantityContract(system: "http://unitsofmeasure.org", code: "1", unit: "1") + let reading = value ?? unit.valueDomain.map(insideValue) ?? 1 + var resource = observation(code: (contract.code.system, contract.code.code), quantity: quantity(unit.code, unit: unit.unit, value: reading, system: unit.system)) + if contract.effective == .period { + resource["effectiveDateTime"] = nil + resource["effectivePeriod"] = ["start": "2026-08-17T15:30:00-07:00", "end": "2026-08-17T15:31:00-07:00"] + } + return resource + } + + /// The middle of a bounded domain, or one past its lower bound, whole when the domain admits only integers. + static func insideValue(_ domain: QuantityValueDomain) -> Double { + var value = domain.maximum.map { (domain.minimum.value + $0.value) / 2 } ?? domain.minimum.value + 1 + var rounded = Decimal() + NSDecimalRound(&rounded, &value, domain.integerOnly ? 0 : 3, .plain) + return NSDecimalNumber(decimal: rounded).doubleValue + } + + static func observation(code: (system: String, code: String), quantity: [String: Any]) -> [String: Any] { + [ + "resourceType": "Observation", + "status": "final", + "code": ["coding": [["system": code.system, "code": code.code]]], + "effectiveDateTime": "2026-08-17T15:30:00-07:00", + "valueQuantity": quantity + ] + } + + static func quantity(_ code: String, unit: String, value: Double, system: String = "http://unitsofmeasure.org") -> [String: Any] { + ["system": system, "code": code, "unit": unit, "value": value] + } + + /// A blood-pressure panel of 120/80, or of the systolic reading alone, in `unit`. + static func bloodPressure(diastolic: Bool, unit: String = "mm[Hg]") -> [String: Any] { + let contract = MeasurementCatalog.bloodPressure + let components = contract.components.filter { diastolic || $0.id == "systolic" }.map { component -> [String: Any] in + [ + "code": ["coding": [["system": component.system, "code": component.code]]], + "valueQuantity": quantity(unit, unit: unit, value: component.id == "systolic" ? 120 : 80) + ] + } + var resource = observation(code: (contract.code.system, contract.code.code), quantity: [:]) + resource["valueQuantity"] = nil + resource["component"] = components + return resource + } + + /// The resource as compact JSON with sorted members. + static func json(_ resource: [String: Any]) -> String { + guard let data = try? JSONSerialization.data(withJSONObject: resource, options: [.sortedKeys, .withoutEscapingSlashes]) else { + preconditionFailure("every corpus Observation is valid JSON") + } + return String(decoding: data, as: UTF8.self) + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Clinical.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Clinical.swift new file mode 100644 index 000000000..3bc8bd1a0 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Clinical.swift @@ -0,0 +1,70 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) && !os(watchOS) + +import Foundation +import GroveFHIRContract +import HealthKit + + +/// CDA documents and clinical records, which watchOS does not have. +extension ContentCorpusGrid { + /// A provider's R4 resource, carried byte for byte. + static let clinicalResource = #"{"resourceType":"Observation","id":"r4"}"# + + /// The goldens' CDA document, then a blank and a padded title, an empty document and none at all, and every link. + static var cdaDocuments: [ContentCorpusVector] { + func document(_ label: String, title: String, document: String?) -> ContentCorpusVector { + convert("cda/\(label)", ContentCorpusSource(.cdaDocument(title: title, document: document), end: start + 1)) + } + let xml = GoldenCase.clinicalDocumentXML + var linked = ContentCorpusSource(.cdaDocument(title: "Grove Golden Summary", document: xml), end: start + 1) + linked.device = .watch + linked.context = .linked + linked.metadata[HKMetadataKeyWasUserEntered] = .boolean(true) + return [ + document("row", title: "Grove Golden Summary", document: xml), + document("blank-title", title: " ", document: xml), + document("padded-title", title: " Summary\n", document: xml), + document("empty-document", title: "Grove Golden Summary", document: ""), + document("no-document", title: "Grove Golden Summary", document: nil), + convert("cda/linked", linked) + ] + } + + /// Every clinical type in R4, then DSTU2, an unknown release, payloads the guides refuse, a missing resource, + /// bytes kept with their whitespace, every link, and which refusal comes first. + static var clinicalRecords: [ContentCorpusVector] { + let labResult = HKClinicalTypeIdentifier.labResultRecord.rawValue + func record(_ label: String, type: String = labResult, version: String = "4.0.1", resource: String? = clinicalResource) -> ContentCorpusVector { + convert("clinical/\(label)", ContentCorpusSource(.clinicalRecord(type: type, fhirVersion: version, resource: resource), end: start)) + } + let types = rows(prefix: "HKClinicalTypeIdentifier").map { record("type/\($0.sourceTypeIdentifier)", type: $0.sourceTypeIdentifier) } + var linked = ContentCorpusSource(.clinicalRecord(type: labResult, fhirVersion: "4.0.1", resource: clinicalResource)) + linked.device = .watch + linked.context = .linked + linked.metadata[HKMetadataKeyWasUserEntered] = .boolean(true) + let duplicateMember = #"{"resourceType":"Observation","resourceType":"Patient"}"# + return types + [ + record("dstu2", version: "1.0.2", resource: #"{"resourceType":"Observation","id":"dstu2"}"#), + record("unknown-release", version: "3.0.1"), + record("undecodable/duplicate-member", resource: duplicateMember), + record("undecodable/lowercase-type", resource: #"{"resourceType":"observation"}"#), + record("undecodable/byte-order-mark", resource: "\u{FEFF}" + clinicalResource), + record("undecodable/array", resource: "[]"), + record("no-resource", resource: nil), + record("whitespace-kept", resource: " {\n \"resourceType\": \"Observation\", \"id\": \"r4\"\n}\n"), + convert("clinical/linked", linked), + record("precedence/release-before-payload", version: "3.0.1", resource: duplicateMember), + record("precedence/empty-before-release", version: "3.0.1", resource: nil) + ] + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Metadata.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Metadata.swift new file mode 100644 index 000000000..b1c3c7cd8 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Metadata.swift @@ -0,0 +1,212 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +import GroveFHIRContract +import HealthKit + + +/// Each metadata key valid, wrongly typed and absent, keys a path does not read, and multi-fault precedence. +extension ContentCorpusGrid { + static let heartRateRecord = ContentCorpusRecord.quantity(type: heartRate, value: 72, unit: "count/min") + + /// Every metadata family, in corpus order. + static var metadata: [ContentCorpusVector] { + typedMetadata + userEntered + syncIdentity + unmodeledMetadata + devices + } + + /// The four keys a single measurement reads: heart-rate motion context, insulin delivery reason, menstrual + /// cycle start and sexual-activity protection, each absent, at every admitted value, out of range and mistyped. + static var typedMetadata: [ContentCorpusVector] { + func family(_ name: String, _ record: ContentCorpusRecord, key: String, _ values: [(String, ContentCorpusMetadataValue?)]) -> [ContentCorpusVector] { + values.map { label, value in + var metadata = zone + metadata[key] = value + return convert("metadata/\(name)/\(label)", ContentCorpusSource(record, end: start + span(record), metadata: metadata)) + } + } + func integers(_ values: [Int], prefix: String = "") -> [(String, ContentCorpusMetadataValue?)] { + values.map { ("\(prefix)\($0)", .integer($0)) } + } + let insulin = ContentCorpusRecord.quantity(type: HKQuantityTypeIdentifier.insulinDelivery.rawValue, value: 2.5, unit: "IU") + let flow = ContentCorpusRecord.category(type: HKCategoryTypeIdentifier.menstrualFlow.rawValue, value: 2) + let activity = ContentCorpusRecord.category(type: HKCategoryTypeIdentifier.sexualActivity.rawValue, value: 0) + let booleans: [(String, ContentCorpusMetadataValue?)] = [("absent", nil), ("true", .boolean(true)), ("false", .boolean(false))] + return family( + "heart-rate-motion-context", + heartRateRecord, + key: HKMetadataKeyHeartRateMotionContext, + [("absent", nil)] + integers([0, 1, 2, 3, -1]) + [("string", .string("1")), ("boolean", .boolean(true)), ("double", .double(1.5))] + ) + family( + "insulin-delivery-reason", + insulin, + key: HKMetadataKeyInsulinDeliveryReason, + [("absent", nil)] + integers([1, 2, 0, 3]) + [("string", .string("1")), ("boolean", .boolean(true)), ("double", .double(2))] + ) + family( + "menstrual-cycle-start", + flow, + key: HKMetadataKeyMenstrualCycleStart, + booleans + integers([1, 0, 2], prefix: "integer-") + [("string", .string("true")), ("double", .double(1))] + ) + family( + "sexual-activity-protection", + activity, + key: HKMetadataKeySexualActivityProtectionUsed, + booleans + integers([1, 2], prefix: "integer-") + [("string", .string("yes"))] + ) + } + + /// `HKMetadataKeyWasUserEntered` on an Observation path in every type, and on a document, which never carries it. + static var userEntered: [ContentCorpusVector] { + let values: [(String, ContentCorpusMetadataValue)] = [ + ("true", .boolean(true)), ("false", .boolean(false)), ("integer-1", .integer(1)), ("integer-2", .integer(2)), ("string", .string("true")) + ] + let observations = values.map { label, value in + convert("metadata/was-user-entered/\(label)", ContentCorpusSource(heartRateRecord, metadata: zone.merging([HKMetadataKeyWasUserEntered: value]) { $1 })) + } + let document = convert( + "metadata/was-user-entered/heartbeat-series", + ContentCorpusSource(.heartbeatSeries(beats: heartbeats), end: start + 2, metadata: zone.merging([HKMetadataKeyWasUserEntered: .boolean(true)]) { $1 }) + ) + return observations + [document] + } + + /// The sync pair whole, halved, empty and mistyped, with and without a writer to attribute it to. + static var syncIdentity: [ContentCorpusVector] { + func pair(_ identifier: ContentCorpusMetadataValue?, _ version: ContentCorpusMetadataValue?) -> [String: ContentCorpusMetadataValue] { + var metadata = zone + metadata[HKMetadataKeySyncIdentifier] = identifier + metadata[HKMetadataKeySyncVersion] = version + return metadata + } + let identifier = ContentCorpusMetadataValue.string("sync-abc") + let pairs: [(String, [String: ContentCorpusMetadataValue])] = [ + ("pair", pair(identifier, .integer(3))), ("identifier-only", pair(identifier, nil)), ("version-only", pair(nil, .integer(3))), + ("empty-identifier", pair(.string(""), .integer(3))), ("identifier-number", pair(.integer(7), .integer(3))), + ("version-string", pair(identifier, .string("3"))), ("version-boolean", pair(identifier, .boolean(true))), + ("version-negative", pair(identifier, .integer(-1))), ("version-fractional", pair(identifier, .double(2.5))), + ("version-zero", pair(identifier, .integer(0))), ("version-integral-double", pair(identifier, .double(3))) + ] + let attributed = pairs.map { label, metadata in + convert("metadata/sync/\(label)", ContentCorpusSource(heartRateRecord, metadata: metadata, writer: .foreign)) + } + return attributed + [convert("metadata/sync/pair-without-writer", ContentCorpusSource(heartRateRecord, metadata: pair(identifier, .integer(3))))] + } + + /// Keys no path reads, and keys one path reads stated on another: today every allowlisted key passes silently. + static var unmodeledMetadata: [ContentCorpusVector] { + func with(_ keys: [String: ContentCorpusMetadataValue]) -> [String: ContentCorpusMetadataValue] { + zone.merging(keys) { _, new in new } + } + let bodyMass = ContentCorpusRecord.quantity(type: HKQuantityTypeIdentifier.bodyMass.rawValue, value: 70, unit: "kg") + let steps = ContentCorpusRecord.quantity(type: HKQuantityTypeIdentifier.stepCount.rawValue, value: 120, unit: "count") + let series = ContentCorpusRecord.heartbeatSeries(beats: heartbeats) + let external: [String: ContentCorpusMetadataValue] = [HKMetadataKeyExternalUUID: .string("external-1")] + let custom: [String: ContentCorpusMetadataValue] = ["org.example.flag": .boolean(true)] + let cases: [(String, ContentCorpusSource)] = [ + ("heart-rate/external-uuid", ContentCorpusSource(heartRateRecord, metadata: with(external))), + ("heart-rate/custom", ContentCorpusSource(heartRateRecord, metadata: with(custom))), + ("heart-rate/both", ContentCorpusSource(heartRateRecord, metadata: with(external.merging(custom) { _, new in new }))), + ("heart-rate/menstrual-cycle-start", ContentCorpusSource(heartRateRecord, metadata: with([HKMetadataKeyMenstrualCycleStart: .boolean(true)]))), + ("heart-rate/insulin-delivery-reason", ContentCorpusSource(heartRateRecord, metadata: with([HKMetadataKeyInsulinDeliveryReason: .integer(1)]))), + ("heart-rate/ecg-algorithm-version", ContentCorpusSource(heartRateRecord, metadata: with([HKMetadataKeyAppleECGAlgorithmVersion: .integer(2)]))), + ( + "heart-rate/sexual-activity-protection", + ContentCorpusSource(heartRateRecord, metadata: with([HKMetadataKeySexualActivityProtectionUsed: .boolean(true)])) + ), + ("body-mass/heart-rate-motion-context", ContentCorpusSource(bodyMass, metadata: with([HKMetadataKeyHeartRateMotionContext: .integer(1)]))), + ( + "step-count/insulin-delivery-reason", + ContentCorpusSource(steps, end: start + 60, metadata: with([HKMetadataKeyInsulinDeliveryReason: .integer(1)])) + ), + ("heartbeat-series/custom", ContentCorpusSource(series, end: start + 2, metadata: with(custom))), + ( + "heartbeat-series/menstrual-cycle-start", + ContentCorpusSource(series, end: start + 2, metadata: with([HKMetadataKeyMenstrualCycleStart: .boolean(true)])) + ), + ("heartbeat-series/zone-only", ContentCorpusSource(series, end: start + 2)) + ] + return cases.map { label, source in + convert("metadata/unmodeled/\(label)", source) + } + } + + /// A recording device with and without a per-unit token. + static var devices: [ContentCorpusVector] { + [(ContentCorpusSource.Device.watch, "watch"), (.watchWithoutUnitToken, "watch-without-unit-token")].map { device, label in + var source = ContentCorpusSource(heartRateRecord) + source.device = device + return convert("metadata/device/\(label)", source) + } + } + + /// Two faults at once: which one the conversion reports pins the order its checks run in. + static var precedence: [ContentCorpusVector] { + let invalidZone: [String: ContentCorpusMetadataValue] = [HKMetadataKeyTimeZone: .string("Not/A-Time-Zone")] + let nanHeartRate = ContentCorpusRecord.quantity(type: heartRate, value: .nan, unit: "count/min") + let steps = HKQuantityTypeIdentifier.stepCount.rawValue + let badSync: [String: ContentCorpusMetadataValue] = [HKMetadataKeySyncIdentifier: .string("sync-abc"), HKMetadataKeySyncVersion: .string("3")] + let motion: [String: ContentCorpusMetadataValue] = [HKMetadataKeyHeartRateMotionContext: .integer(3)] + let cases: [(String, ContentCorpusSource)] = [ + ("zone-before-value", ContentCorpusSource(nanHeartRate, metadata: invalidZone)), + ("zone-before-motion-context", ContentCorpusSource(heartRateRecord, metadata: invalidZone.merging(motion) { $1 })), + ("value-before-motion-context", ContentCorpusSource(nanHeartRate, metadata: zone.merging(motion) { $1 })), + ("effective-before-value", ContentCorpusSource(.quantity(type: steps, value: .nan, unit: "count"))), + ("zone-before-effective", ContentCorpusSource(.quantity(type: steps, value: 120, unit: "count"), end: start - 60, metadata: invalidZone)), + ("value-before-protection", ContentCorpusSource( + .category(type: HKCategoryTypeIdentifier.sexualActivity.rawValue, value: 1), + metadata: zone.merging([HKMetadataKeySexualActivityProtectionUsed: .string("yes")]) { $1 } + )), + ("value-before-cycle-start", ContentCorpusSource(.category(type: HKCategoryTypeIdentifier.menstrualFlow.rawValue, value: 9), end: start + 60)), + ("value-before-insulin-reason", ContentCorpusSource(.quantity(type: HKQuantityTypeIdentifier.insulinDelivery.rawValue, value: .nan, unit: "IU"))), + ("value-before-sync", ContentCorpusSource(nanHeartRate, metadata: zone.merging(badSync) { $1 }, writer: .foreign)), + ("motion-context-before-sync", ContentCorpusSource(heartRateRecord, metadata: zone.merging(badSync.merging(motion) { $1 }) { $1 }, writer: .foreign)), + ("zone-before-missing-member", ContentCorpusSource( + .correlation(type: bloodPressure, members: [ContentCorpusMember(type: HKQuantityTypeIdentifier.bloodPressureDiastolic.rawValue, value: 80)]), + metadata: invalidZone + )), + ("first-member-first", ContentCorpusSource(.correlation(type: bloodPressure, members: [ + ContentCorpusMember(type: HKQuantityTypeIdentifier.bloodPressureSystolic.rawValue, value: .nan), + ContentCorpusMember(type: HKQuantityTypeIdentifier.bloodPressureDiastolic.rawValue, value: -1) + ]))), + ("effective-before-value-year-10000", ContentCorpusSource(nanHeartRate, start: 253_402_300_800, metadata: [:])), + ("effective-before-category-value", ContentCorpusSource( + .category(type: HKCategoryTypeIdentifier.sleepAnalysis.rawValue, value: 9), + end: start - 60 + )), + ("zone-before-workout-duration", ContentCorpusSource( + .workout(activity: HKWorkoutActivityType.running.rawValue, duration: .nan, statistics: []), + end: start + 3_600, + metadata: invalidZone + )), + ("zone-before-assessment-score", ContentCorpusSource( + .assessment(type: HKScoredAssessmentTypeIdentifier.GAD7.rawValue, score: 99), + metadata: invalidZone + )), + ("empty-series-before-sync", ContentCorpusSource(.heartbeatSeries(beats: []), end: start + 2, metadata: zone.merging(badSync) { $1 }, writer: .foreign)), + ("value-before-unmodeled-warning", ContentCorpusSource(nanHeartRate, metadata: zone.merging(["org.example.flag": .boolean(true)]) { $1 })) + ] + var deviceOmission = ContentCorpusSource(nanHeartRate) + deviceOmission.device = .watchWithoutUnitToken + return (cases + [("value-before-device-omission", deviceOmission)]).map { label, source in + convert("precedence/\(label)", source) + } + } + + /// How long a record of the row lasts; a record of another kind is an instant. + static func span(_ record: ContentCorpusRecord) -> Double { + let type: String? = switch record { + case .quantity(let type, _, _), .category(let type, _): type + default: nil + } + return span(HealthKitContract.rows.first { $0.sourceTypeIdentifier == type }.flatMap(contract)) + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Recordings.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Recordings.swift new file mode 100644 index 000000000..948989f33 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Recordings.swift @@ -0,0 +1,238 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +import GroveFHIRContract +import HealthKit + + +/// ECG evidence edges and every recording and clinical document builder. +extension ContentCorpusGrid { + /// The conformance fixtures' sinus-rhythm reading: four voltages 2 ms apart at 500 Hz, 72 bpm, no symptoms. + static let electrocardiogramReading = ContentCorpusElectrocardiogram( + classification: HKElectrocardiogram.Classification.sinusRhythm.rawValue, + symptomsStatus: HKElectrocardiogram.SymptomsStatus.none.rawValue, + reportedCount: 4, + averageHeartRate: 72, + samplingFrequency: 500, + voltages: [(0.25, 0.125), (0.252, 0.25), (0.254, -0.125), (0.256, 0)].map { ContentCorpusElectrocardiogram.Voltage(offset: $0, millivolts: $1) } + ) + + /// The zone and algorithm version an Apple Watch ECG states. + static let electrocardiogramMetadata = zone.merging([HKMetadataKeyAppleECGAlgorithmVersion: .integer(2)]) { _, new in new } + + /// Three beats, the last after a gap. + static let heartbeats = [ + ContentCorpusBeat(offset: 0, gap: false), ContentCorpusBeat(offset: 0.84, gap: false), ContentCorpusBeat(offset: 1.71, gap: true) + ] + + /// The goldens' two fixes one second apart; the second reports no vertical accuracy, course or speed. + static let routeLocations = [ + ContentCorpusLocation( + offset: 0, + latitude: 37.4275, + longitude: -122.1697, + altitude: 30.5, + horizontalAccuracy: 5, + verticalAccuracy: 3, + course: 91.5, + courseAccuracy: 10, + speed: 2.25, + speedAccuracy: 0.5 + ), + ContentCorpusLocation( + offset: 1, + latitude: 37.4276, + longitude: -122.1698, + altitude: 0, + horizontalAccuracy: 65, + verticalAccuracy: -1, + course: -1, + courseAccuracy: -1, + speed: -1, + speedAccuracy: -1 + ) + ] + + /// Every classification, symptoms status and algorithm version, average heart rate and sampling frequency + /// edges, every waveform refusal, zones, symptom relationships, and the plain sample entry point. + static var electrocardiograms: [ContentCorpusVector] { + let averages: [(String, Double?)] = [("none", nil), ("fraction", 72.5), ("nan", .nan), ("zero", 0), ("tiny", 1e-7)] + let frequencies: [(String, Double?)] = [("none", nil), ("mismatch", 250), ("zero", 0), ("nan", .nan), ("negative", -500), ("near", 499.99)] + let readings: [(String, ContentCorpusElectrocardiogram)] = [("row", electrocardiogramReading)] + + [0, 2, 3, 4, 5, 6, 100, 99].map { raw in ("classification/\(raw)", reading { $0.classification = raw }) } + + [0, 99].map { status in ("symptoms-status/\(status)", reading { $0.symptomsStatus = status }) } + + averages.map { label, rate in ("average-heart-rate/\(label)", reading { $0.averageHeartRate = rate }) } + + frequencies.map { label, rate in ("sampling-frequency/\(label)", reading { $0.samplingFrequency = rate }) } + + waveformEdges + + symptomRelationships + return readings.map { label, reading in electrocardiogram(label, reading) } + electrocardiogramFacts + } + + /// Correlated symptoms: one, several sorted by type and UUID, refused types and duplicates, a status that + /// contradicts them, an invalid symptom value, a missing context, and what fails first beside them. + static var symptomRelationships: [(String, ContentCorpusElectrocardiogram)] { + let present = HKElectrocardiogram.SymptomsStatus.present.rawValue + let chest = HKCategoryTypeIdentifier.chestTightnessOrPain.rawValue + let fatigue = HKCategoryTypeIdentifier.fatigue.rawValue + let headache = HKCategoryTypeIdentifier.headache.rawValue + func symptom(_ type: String, _ value: Int, _ ordinal: UInt8) -> ContentCorpusElectrocardiogram.Symptom { + ContentCorpusElectrocardiogram.Symptom(type: type, value: value, ordinal: ordinal) + } + return [ + ("symptoms/one", symptoms(present, [symptom(chest, 2, 0xE1)])), + ("symptoms/two-types", symptoms(present, [symptom(fatigue, 2, 0xE2), symptom(chest, 3, 0xE1)])), + ("symptoms/same-type", symptoms(present, [symptom(chest, 2, 0xE4), symptom(chest, 4, 0xE3)])), + ("symptoms/unsupported-type", symptoms(present, [symptom(headache, 2, 0xE1)])), + ("symptoms/duplicate-source", symptoms(present, [symptom(chest, 2, 0xE1), symptom(fatigue, 2, 0xE1)])), + ("symptoms/unexpected", symptoms(HKElectrocardiogram.SymptomsStatus.none.rawValue, [symptom(chest, 2, 0xE1)])), + ("symptoms/required", symptoms(present, [])), + ("symptoms/invalid-value", symptoms(present, [symptom(chest, 9, 0xE1)])), + ("symptoms/context-missing", reading(symptoms(present, [symptom(chest, 2, 0xE1)])) { $0.symptomContexts = 0 }), + ("precedence/symptoms-before-classification", reading(symptoms(present, [symptom(headache, 2, 0xE1)])) { $0.classification = 99 }), + ("precedence/count-before-average-heart-rate", reading { reading in + reading.reportedCount = 3 + reading.averageHeartRate = .nan + }) + ] + } + + /// Waveform refusals: counts, offsets, voltages and lead presence. + static var waveformEdges: [(String, ContentCorpusElectrocardiogram)] { + func offsets(_ values: [Double]) -> ContentCorpusElectrocardiogram { + reading { reading in + reading.voltages = zip(values, reading.voltages).map { offset, voltage in + ContentCorpusElectrocardiogram.Voltage(offset: offset, millivolts: voltage.millivolts) + } + } + } + func voltage(at index: Int, _ millivolts: Double?) -> ContentCorpusElectrocardiogram { + reading { $0.voltages[index].millivolts = millivolts } + } + return [ + ("count/zero", reading { $0.reportedCount = 0 }), + ("count/mismatch", reading { $0.reportedCount = 3 }), + ("count/one", reading { reading in + reading.reportedCount = 1 + reading.voltages = Array(reading.voltages.prefix(1)) + }), + ("offsets/negative", offsets([-0.002, 0, 0.002, 0.004])), + ("offsets/repeated", offsets([0.25, 0.25, 0.252, 0.254])), + ("offsets/non-uniform", offsets([0.25, 0.252, 0.255, 0.256])), + ("offsets/nan", offsets([0.25, .nan, 0.254, 0.256])), + ("voltages/nan", voltage(at: 1, .nan)), + ("voltages/missing-lead", voltage(at: 2, nil)), + ("voltages/tiny", voltage(at: 1, 1e-7)), + ("voltages/huge", voltage(at: 1, 1e21)) + ] + } + + /// The ECG's own facts: zones, algorithm versions, manual entry, a reversed interval, every link, and the + /// plain sample entry point, which has no voltages to convert. + static var electrocardiogramFacts: [ContentCorpusVector] { + let version = HKMetadataKeyAppleECGAlgorithmVersion + let metadata: [(String, [String: ContentCorpusMetadataValue])] = [ + ("zone/none", [version: .integer(2)]), + ("zone/invalid", [HKMetadataKeyTimeZone: .string("Not/A-Time-Zone"), version: .integer(2)]), + ("zone/kathmandu", [HKMetadataKeyTimeZone: .string("Asia/Kathmandu"), version: .integer(2)]), + ("algorithm-version/absent", zone), ("algorithm-version/1", zone.merging([version: .integer(1)]) { $1 }), + ("algorithm-version/3", zone.merging([version: .integer(3)]) { $1 }), + ("algorithm-version/string", zone.merging([version: .string("2")]) { $1 }), + ("algorithm-version/double", zone.merging([version: .double(2)]) { $1 }), + ("user-entered", electrocardiogramMetadata.merging([HKMetadataKeyWasUserEntered: .boolean(true)]) { $1 }) + ] + var reversed = electrocardiogramSource(electrocardiogramReading) + reversed.end = start - 30 + var linked = electrocardiogramSource(electrocardiogramReading) + linked.device = .watch + linked.context = .linked + linked.metadata[HKMetadataKeyWasUserEntered] = .boolean(true) + var zoneFirst = electrocardiogramSource(reading { $0.reportedCount = 3 }) + zoneFirst.metadata[HKMetadataKeyTimeZone] = .string("Not/A-Time-Zone") + return metadata.map { label, metadata in + var source = electrocardiogramSource(electrocardiogramReading) + source.metadata = metadata + return convert("electrocardiogram/\(label)", source) + } + [ + convert("electrocardiogram/reversed", reversed), + convert("electrocardiogram/linked", linked), + convert("electrocardiogram/precedence/zone-before-count", zoneFirst), + convert( + "electrocardiogram/sample-entry", + ContentCorpusSource(.bare(type: HKObjectType.electrocardiogramType().identifier, sampleClass: "HKElectrocardiogram"), end: start + 30) + ) + ] + } + + /// Heartbeat series and workout routes: their payloads, empty series, every link, and the plain sample entry point. + static var recordings: [ContentCorpusVector] { + func series(_ label: String, _ beats: [ContentCorpusBeat], metadata: [String: ContentCorpusMetadataValue] = zone) -> ContentCorpusVector { + convert("heartbeat-series/\(label)", ContentCorpusSource(.heartbeatSeries(beats: beats), end: start + 2, metadata: metadata)) + } + func route(_ label: String, _ locations: [ContentCorpusLocation], disclosed: Bool = true) -> ContentCorpusVector { + convert("workout-route/\(label)", ContentCorpusSource(.workoutRoute(locations: locations, disclosed: disclosed), end: start + 1)) + } + let unavailable = routeLocations.map { fix in + var fix = fix + fix.verticalAccuracy = -1 + fix.course = -1 + fix.courseAccuracy = -1 + fix.speed = -1 + fix.speedAccuracy = -1 + return fix + } + var linkedSeries = ContentCorpusSource(.heartbeatSeries(beats: heartbeats), end: start + 2) + var linkedRoute = ContentCorpusSource(.workoutRoute(locations: routeLocations, disclosed: true), end: start + 1) + linkedSeries.device = .watch + linkedSeries.context = .linked + linkedRoute.device = .watch + linkedRoute.context = .linked + return [ + series("row", heartbeats), series("empty", []), series("single", [heartbeats[0]]), + series("fractional", [ContentCorpusBeat(offset: 0.1 + 0.2, gap: false), ContentCorpusBeat(offset: 1e-7, gap: true)]), + series("late", [ContentCorpusBeat(offset: 86_400.5, gap: false)]), + series("zone-invalid", heartbeats, metadata: [HKMetadataKeyTimeZone: .string("Not/A-Time-Zone")]), + convert("heartbeat-series/linked", linkedSeries), + convert("heartbeat-series/sample-entry", ContentCorpusSource(.bare(type: HKSeriesType.heartbeat().identifier, sampleClass: "HKHeartbeatSeriesSample"))), + route("row", routeLocations), route("omitted", routeLocations, disclosed: false), route("empty", []), + route("unavailable-readings", unavailable), + convert("workout-route/linked", linkedRoute), + convert("workout-route/sample-entry", ContentCorpusSource(.bare(type: HKSeriesType.workoutRoute().identifier, sampleClass: "HKWorkoutRoute"))) + ] + } + + /// The base reading with one change. + static func reading( + _ base: ContentCorpusElectrocardiogram = electrocardiogramReading, + _ change: (inout ContentCorpusElectrocardiogram) -> Void + ) -> ContentCorpusElectrocardiogram { + var reading = base + change(&reading) + return reading + } + + /// The base reading under `status`, with `samples` correlated. + static func symptoms(_ status: Int, _ samples: [ContentCorpusElectrocardiogram.Symptom]) -> ContentCorpusElectrocardiogram { + reading { reading in + reading.symptomsStatus = status + reading.symptoms = samples + } + } + + static func electrocardiogramSource(_ reading: ContentCorpusElectrocardiogram) -> ContentCorpusSource { + ContentCorpusSource(.electrocardiogram(reading: reading), end: start + 30, metadata: electrocardiogramMetadata) + } + + static func electrocardiogram(_ label: String, _ reading: ContentCorpusElectrocardiogram) -> ContentCorpusVector { + convert("electrocardiogram/\(label)", electrocardiogramSource(reading)) + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Records.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Records.swift new file mode 100644 index 000000000..686703e61 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Records.swift @@ -0,0 +1,194 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +import GroveFHIRContract +import HealthKit + + +/// Correlations, workouts, State of Mind, scored assessments and the rows only a bare sample reaches. +extension ContentCorpusGrid { + /// The distance types a workout may total, each with its own sum so the vector shows which one is read. + static let distanceStatistics: [ContentCorpusStatistic] = [ + HKQuantityTypeIdentifier.distanceWalkingRunning, .distanceCycling, .distanceSwimming, .distanceWheelchair, + .distanceCrossCountrySkiing, .distanceRowing, .distanceDownhillSnowSports, .distancePaddleSports, .distanceSkatingSports + ].enumerated().map { index, type in + ContentCorpusStatistic(type: type.rawValue, unit: "m", sum: 1_001 + Double(index)) + } + + /// Blood pressure: the pair, missing and extra members, member values, and member metadata of every kind. + static var correlations: [ContentCorpusVector] { + let systolic = HKQuantityTypeIdentifier.bloodPressureSystolic.rawValue + let diastolic = HKQuantityTypeIdentifier.bloodPressureDiastolic.rawValue + let kolkata: [String: ContentCorpusMetadataValue] = [HKMetadataKeyTimeZone: .string("Asia/Kolkata")] + let kathmandu: [String: ContentCorpusMetadataValue] = [HKMetadataKeyTimeZone: .string("Asia/Kathmandu")] + func pair( + systolic systolicMetadata: [String: ContentCorpusMetadataValue] = [:], + diastolic diastolicMetadata: [String: ContentCorpusMetadataValue] = [:] + ) -> [ContentCorpusMember] { + [ + ContentCorpusMember(type: systolic, value: 120, metadata: systolicMetadata), + ContentCorpusMember(type: diastolic, value: 80, metadata: diastolicMetadata) + ] + } + func pressure( + _ label: String, + _ members: [ContentCorpusMember], + metadata: [String: ContentCorpusMetadataValue] = zone, + end: Double = start + ) -> ContentCorpusVector { + convert("correlation/blood-pressure/\(label)", ContentCorpusSource(.correlation(type: bloodPressure, members: members), end: end, metadata: metadata)) + } + let sync: [String: ContentCorpusMetadataValue] = [HKMetadataKeySyncIdentifier: .string("member-sync"), HKMetadataKeySyncVersion: .integer(1)] + return [ + pressure("row", pair()), pressure("interval", pair(), end: start + 60), + pressure("missing-systolic", [pair()[1]]), pressure("missing-diastolic", [pair()[0]]), pressure("no-members", []), + pressure("extra-heart-rate", pair() + [ContentCorpusMember(type: heartRate, value: 60, unit: "count/min")]), + pressure("systolic-nan", [ContentCorpusMember(type: systolic, value: .nan), pair()[1]]), + pressure("systolic-negative", [ContentCorpusMember(type: systolic, value: -1), pair()[1]]), + pressure("systolic-huge", [ContentCorpusMember(type: systolic, value: 1e21), pair()[1]]), + pressure("systolic-fractional", [ContentCorpusMember(type: systolic, value: 120.5), pair()[1]]), + pressure("diastolic-zero", [pair()[0], ContentCorpusMember(type: diastolic, value: 0)]), + pressure("member-zone-differs", pair(systolic: kolkata)), + pressure("member-zones-agree-correlation-none", pair(systolic: kolkata, diastolic: kolkata), metadata: [:]), + pressure("member-zones-disagree-correlation-none", pair(systolic: kolkata, diastolic: kathmandu), metadata: [:]), + pressure("member-zone-invalid-correlation-none", pair(systolic: [HKMetadataKeyTimeZone: .string("Not/A-Time-Zone")]), metadata: [:]), + pressure("member-user-entered", pair(systolic: [HKMetadataKeyWasUserEntered: .boolean(true)])), + pressure( + "member-user-entered-correlation-not", + pair(diastolic: [HKMetadataKeyWasUserEntered: .boolean(true)]), + metadata: zone.merging([HKMetadataKeyWasUserEntered: .boolean(false)]) { _, new in new } + ), + pressure("member-foreign-key", pair(diastolic: ["org.example.member": .string("x")])), + pressure("member-sync-identity", pair(systolic: sync)), + convert("correlation/food/row", ContentCorpusSource(.correlation( + type: HKCorrelationTypeIdentifier.food.rawValue, + members: [ContentCorpusMember(type: HKQuantityTypeIdentifier.dietaryEnergyConsumed.rawValue, value: 320, unit: "kcal")] + ))) + ] + } + + /// Every activity raw (with every distance type, so the vector shows which one counts), each statistic alone + /// and together, unusual readings and durations. + static var workouts: [ContentCorpusVector] { + let running = HKWorkoutActivityType.running.rawValue + let sweep = ((0...90).map(UInt.init) + [3_000, 9_999]).map { raw in + convert("workout/activity/\(raw)", workout(raw, statistics: distanceStatistics)) + } + let statistics = workoutStatistics.map { label, statistics in + convert("workout/statistics/\(label)", workout(running, statistics: statistics)) + } + let durations = [("zero", 0.0), ("fractional", 1.5), ("negative", -1), ("nan", .nan)].map { label, duration in + convert( + "workout/duration/\(label)", + ContentCorpusSource(.workout(activity: running, duration: duration, statistics: []), end: start + 3_600) + ) + } + var reversed = workout(running, statistics: []) + reversed.end = start - 60 + var userEntered = workout(running, statistics: []) + userEntered.metadata[HKMetadataKeyWasUserEntered] = .boolean(true) + return sweep + statistics + durations + [convert("workout/reversed", reversed), convert("workout/user-entered", userEntered)] + } + + /// Each workout statistic alone, all of them, partial heart-rate readings, and readings no contract admits. + static var workoutStatistics: [(String, [ContentCorpusStatistic])] { + func statistic(_ type: HKQuantityTypeIdentifier, _ unit: String, sum: Double? = nil, average: Double? = nil) -> ContentCorpusStatistic { + ContentCorpusStatistic(type: type.rawValue, unit: unit, sum: sum, average: average) + } + func heart(average: Double?, minimum: Double?, maximum: Double?) -> ContentCorpusStatistic { + ContentCorpusStatistic(type: heartRate, unit: "count/min", average: average, minimum: minimum, maximum: maximum) + } + let distance = statistic(.distanceWalkingRunning, "m", sum: 10_000) + let energy = statistic(.activeEnergyBurned, "kcal", sum: 640) + let steps = statistic(.stepCount, "count", sum: 9_000) + let flights = statistic(.flightsClimbed, "count", sum: 12) + let strokes = statistic(.swimmingStrokeCount, "count", sum: 900) + let fullHeart = heart(average: 140, minimum: 95, maximum: 171) + return [ + ("none", []), ("distance", [distance]), ("energy", [energy]), ("steps", [steps]), ("flights", [flights]), + ("strokes", [strokes]), ("heart-rate", [fullHeart]), ("all", [fullHeart, strokes, flights, steps, energy, distance]), + ("heart-rate-average-only", [heart(average: 140, minimum: nil, maximum: nil)]), + ("heart-rate-extremes-only", [heart(average: nil, minimum: 95, maximum: 171)]), + ("heart-rate-without-readings", [heart(average: nil, minimum: nil, maximum: nil)]), + ("heart-rate-nan-average", [heart(average: .nan, minimum: 95, maximum: 171)]), + ("energy-nan", [statistic(.activeEnergyBurned, "kcal", sum: .nan)]), ("energy-zero", [statistic(.activeEnergyBurned, "kcal", sum: 0)]), + ("distance-negative", [statistic(.distanceWalkingRunning, "m", sum: -1)]), ("steps-fractional", [statistic(.stepCount, "count", sum: 1.5)]), + ("energy-average-only", [statistic(.activeEnergyBurned, "kcal", average: 320)]) + ] + } + + /// Kinds, valences across every classification band, and label and association lists of every shape. + static var statesOfMind: [ContentCorpusVector] { + let happy = HKStateOfMind.Label.happy.rawValue + let work = HKStateOfMind.Association.work.rawValue + func reflection( + _ label: String, + kind: Int = 1, + valence: Double = 0.5, + labels: [Int] = [happy], + associations: [Int] = [work], + end: Double = start + ) -> ContentCorpusVector { + convert( + "state-of-mind/\(label)", + ContentCorpusSource(.stateOfMind(kind: kind, valence: valence, labels: labels, associations: associations), end: end) + ) + } + let unsortedLabels = [HKStateOfMind.Label.sad, .angry, .happy, .calm].map(\.rawValue) + let unsortedAssociations = [HKStateOfMind.Association.work, .family, .health, .community].map(\.rawValue) + return [reflection("row"), reflection("interval", end: start + 60)] + + [2, 0, 99].map { reflection("kind/\($0)", kind: $0) } + + [-1, -0.9, -0.6, -0.3, -0.1, 0, 0.1, 0.3, 0.6, 0.9, 1, 0.1 + 0.2].map { reflection("valence/\($0)", valence: $0) } + + [ + reflection("labels/none", labels: []), reflection("labels/every-raw", labels: Array(0...41)), + reflection("labels/unsorted", labels: unsortedLabels), reflection("labels/duplicate", labels: [happy, happy, unsortedLabels[1]]), + reflection("labels/unknown", labels: [999, happy]), + reflection("associations/none", associations: []), reflection("associations/every-raw", associations: Array(0...21)), + reflection("associations/unsorted", associations: unsortedAssociations), + reflection("associations/duplicate", associations: [work, work, unsortedAssociations[1]]), + reflection("associations/unknown", associations: [999, work]) + ] + } + + /// GAD-7 and PHQ-9 scores at and beyond both ends of their ranges. + static var assessments: [ContentCorpusVector] { + [(HKScoredAssessmentTypeIdentifier.GAD7, [-1, 0, 6, 21, 22]), (.PHQ9, [-1, 0, 14, 27, 28])].flatMap { type, scores in + let row = HealthKitContract.rows.first { $0.sourceTypeIdentifier == type.rawValue } + return scores.map { score in + convert( + "assessment/\(type.rawValue)/\(score)", + ContentCorpusSource(.assessment(type: type.rawValue, score: score), end: start + span(row.flatMap(contract))) + ) + } + } + } + + /// The sample rows no other family reaches, each as a bare sample through the plain entry point. + static var bareRows: [ContentCorpusVector] { + [ + (HKObjectType.audiogramSampleType().identifier, "HKAudiogramSample"), + (HKObjectType.visionPrescriptionType().identifier, "HKVisionPrescription"), + (HKObjectType.medicationDoseEventType().identifier, "HKMedicationDoseEvent") + ].map { type, sampleClass in + convert("row/\(type)", ContentCorpusSource(.bare(type: type, sampleClass: sampleClass))) + } + } + + static let bloodPressure = HKCorrelationTypeIdentifier.bloodPressure.rawValue + static let heartRate = HKQuantityTypeIdentifier.heartRate.rawValue + + /// A one-hour workout of `activity` with `statistics`. + static func workout(_ activity: UInt, statistics: [ContentCorpusStatistic]) -> ContentCorpusSource { + ContentCorpusSource(.workout(activity: activity, duration: 3_600, statistics: statistics), end: start + 3_600) + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid.swift new file mode 100644 index 000000000..0ac53fe09 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid.swift @@ -0,0 +1,199 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit + + +/// Every content-corpus vector, generated from the public catalog alone: the input coverage of the step-7 oracle +/// (synthesis section 16, O2), in a fixed order, each under a stable id. +/// +/// Families: every quantity type over a value sweep (and every percent type over fractions), every category type +/// over raw values -1 through 8, effective-time edges for each effective kind, blood-pressure member variants, +/// every workout activity raw with and without statistics, State of Mind permutations, scored assessments, each +/// metadata key valid, wrongly typed and absent, ECG evidence edges, every recording and clinical document +/// builder, multi-fault precedence, retraction targets, and the catalog projections. Vectors are appended, never +/// renumbered: an id names the same input for as long as the corpus exists. +enum ContentCorpusGrid { + /// 2026-08-17T22:30:00Z, 15:30 in Los Angeles: when every vector's record starts unless it states otherwise. + static let start = GoldenFixtures.sampleStart.timeIntervalSince1970 + /// The default metadata: the Los Angeles zone and nothing else. + static let zone: [String: ContentCorpusMetadataValue] = [HKMetadataKeyTimeZone: .string(GoldenFixtures.timeZone)] + + /// The quantity sweep: zero, a fraction, a negative, a tiny and a huge value, and the non-finite values. + static let sweep: [Double] = [0, 1.5, -1, 1e-7, 1e21, .nan, .infinity, -.infinity] + /// Fractions a percent type is stated in, among them the binary64 products that print with a tail. + static let fractions: [Double] = [0.07, 0.14, 0.28, 0.282, 0.29, 0.55, 0.56, 0.57, 0.58, 0.98, 0.5, 1] + + /// Units for quantity types whose contract names no unit the catalog binds, tried in order. + static let fallbackUnits: [HKUnit] = [ + .count(), .millimeterOfMercury(), .percent(), .second(), .meter(), .gramUnit(with: .kilo), .kilocalorie(), + .degreeCelsius(), .count().unitDivided(by: .minute()), .meter().unitDivided(by: .second()), .watt(), + .decibelAWeightedSoundPressureLevel(), .internationalUnit(), .literUnit(with: .milli), .lux(), .siemen(), + .gramUnit(with: .milli).unitDivided(by: .literUnit(with: .deci)), .literUnit(with: .milli).unitDivided(by: .minute()) + ] + + /// Every generated measurement contract by id; the first catalog wins, as everywhere else. + static let contracts: [String: MeasurementContract] = Dictionary( + (MeasurementCatalog.all + HealthKitMeasurementCatalog.all).map { ($0.id, $0) } + ) { first, _ in first } + + /// Every vector, in corpus order. + static var vectors: [ContentCorpusVector] { + quantities + categories + times + correlations + workouts + statesOfMind + assessments + bareRows + + metadata + precedence + electrocardiograms + recordings + clinicalDocuments + retractions + catalog + reverseProjections + } + + /// The vectors of every quantity row: a value the contract admits, the sweep, and for a percent type the fractions. + static var quantities: [ContentCorpusVector] { + rows(prefix: "HKQuantityTypeIdentifier").flatMap { row -> [ContentCorpusVector] in + let identifier = HKQuantityTypeIdentifier(rawValue: row.sourceTypeIdentifier) + let measurement = contract(row) + guard let type = HKObjectType.quantityType(forIdentifier: identifier), let unit = quantityUnit(type, contract: measurement) else { + return [] + } + let isPercent = measurement?.quantity?.code == "%" + let values = [("row", isPercent ? 0.25 : representative(measurement))] + + sweep.map { (String($0), $0) } + + (isPercent ? fractions.map { ("fraction-\($0)", $0) } : []) + return values.map { label, value in + convert( + "quantity/\(row.sourceTypeIdentifier)/\(label)", + ContentCorpusSource(.quantity(type: row.sourceTypeIdentifier, value: value, unit: unit.unitString), end: start + span(measurement)) + ) + } + } + } + + /// The vectors of every category row: each raw value from -1 through 8, past the largest any table admits (7). + static var categories: [ContentCorpusVector] { + rows(prefix: "HKCategoryTypeIdentifier").flatMap { row -> [ContentCorpusVector] in + guard HKObjectType.categoryType(forIdentifier: HKCategoryTypeIdentifier(rawValue: row.sourceTypeIdentifier)) != nil else { + return [] + } + var metadata = zone + if row.sourceTypeIdentifier == HKCategoryTypeIdentifier.menstrualFlow.rawValue { + metadata[HKMetadataKeyMenstrualCycleStart] = .boolean(true) + } + return (-1...8).map { raw in + convert( + "category/\(row.sourceTypeIdentifier)/\(raw)", + ContentCorpusSource(.category(type: row.sourceTypeIdentifier, value: raw), end: start + span(contract(row)), metadata: metadata) + ) + } + } + } + + /// Effective-time edges for a dateTime, a dateTime-or-Period, a Period and a non-zero Period measurement. + static var times: [ContentCorpusVector] { + let records: [ContentCorpusRecord] = [ + .quantity(type: HKQuantityTypeIdentifier.bodyMass.rawValue, value: 70, unit: "kg"), + .quantity(type: HKQuantityTypeIdentifier.heartRate.rawValue, value: 72, unit: "count/min"), + .quantity(type: HKQuantityTypeIdentifier.dietaryEnergyConsumed.rawValue, value: 650, unit: "kcal"), + .quantity(type: HKQuantityTypeIdentifier.stepCount.rawValue, value: 120, unit: "count") + ] + return records.flatMap { record -> [ContentCorpusVector] in + guard case .quantity(let type, _, _) = record else { + return [] + } + let duration = span(HealthKitContract.rows.first { $0.sourceTypeIdentifier == type }.flatMap(contract)) + let intervals = [("equal", 0.0), ("interval-45s", 45), ("reversed-45s", -45)].map { label, offset in + convert("time/\(type)/\(label)", ContentCorpusSource(record, end: start + offset)) + } + let zones = timeZones.map { label, metadata in + convert("time/\(type)/zone-\(label)", ContentCorpusSource(record, end: start + 45, metadata: metadata)) + } + let edges = instants.flatMap { label, instant in + [("none", [:]), ("los-angeles", zone)].map { zoneLabel, metadata in + convert("time/\(type)/\(label)/\(zoneLabel)", ContentCorpusSource(record, start: instant, end: instant + duration, metadata: metadata)) + } + } + return intervals + zones + edges + } + } + + /// No zone, an unknown name, a number, and named zones with odd, half-hour and quarter-hour offsets. + static let timeZones: [(String, [String: ContentCorpusMetadataValue])] = [ + ("none", [:]), + ("invalid", [HKMetadataKeyTimeZone: .string("Not/A-Time-Zone")]), + ("wrong-type", [HKMetadataKeyTimeZone: .integer(42)]), + ("los-angeles", [HKMetadataKeyTimeZone: .string("America/Los_Angeles")]), + ("kolkata", [HKMetadataKeyTimeZone: .string("Asia/Kolkata")]), + ("kathmandu", [HKMetadataKeyTimeZone: .string("Asia/Kathmandu")]), + ("st-johns", [HKMetadataKeyTimeZone: .string("America/St_Johns")]), + ("utc", [HKMetadataKeyTimeZone: .string("UTC")]) + ] + + /// Both occurrences of Los Angeles's repeated 2026 hour, its local mean time in 1800 (a non-minute offset), + /// a .250 fraction, exact half-millisecond ties, the year 9999/10000 and year 1/0 boundaries, and 1500. + static let instants: [(String, Double)] = [ + ("repeated-hour-first", 1_793_521_800), ("repeated-hour-second", 1_793_525_400), ("lmt-1800", -5_364_662_400), + ("fraction-250", 1_787_148_600.25), ("tie-even", 1_787_148_600.0625), ("tie-odd", 1_787_148_600.1875), + ("year-9999", 253_402_300_799), ("year-10000", 253_402_300_800), ("pre-reform-1500", -14_831_769_600), + ("year-1", -62_135_596_800), ("year-0", -62_135_596_801) + ] + + static func convert(_ id: String, _ source: ContentCorpusSource) -> ContentCorpusVector { + ContentCorpusVector(id: id, input: .convert(source: source)) + } + + /// The inventory rows of one identifier family, in row order. + static func rows(prefix: String) -> [HealthKitContractRow] { + HealthKitContract.rows.filter { $0.sourceTypeIdentifier.hasPrefix(prefix) } + } + + /// The generated contract of a row's first measurement, if the catalogs carry one. + static func contract(_ row: HealthKitContractRow) -> MeasurementContract? { + row.measurementIDs.first.flatMap { contracts[$0] } + } + + /// How long a record of the contract lasts: a minute for a Period measurement, an instant otherwise. + static func span(_ contract: MeasurementContract?) -> Double { + contract?.effective == .period ? 60 : 0 + } + + /// The unit the contract's UCUM code binds, else the first fallback unit that measures the type. + static func quantityUnit(_ type: HKQuantityType, contract: MeasurementContract?) -> HKUnit? { + if contract?.quantity?.code == "%" { + return .percent() + } + if let code = contract?.quantity?.code, let unit = HealthKitCatalog.unit(forUCUMCode: code), type.is(compatibleWith: unit) { + return unit + } + return fallbackUnits.first { type.is(compatibleWith: $0) } + } + + /// A value the contract's domain admits, so every row has one vector that converts if anything does. + static func representative(_ contract: MeasurementContract?) -> Double { + guard let domain = contract?.quantity?.valueDomain else { + return 1 + } + return [1, 50, 100, 1_000, 0.5, 0].first { domain.contains(Decimal($0)) } ?? 1 + } +} + + +extension ContentCorpusSource { + /// A record under the default facts: starting at the base instant, in Los Angeles, attributed to no writer, + /// without a device, in the default context. + init( + _ record: ContentCorpusRecord, + start: Double = ContentCorpusGrid.start, + end: Double? = nil, + metadata: [String: ContentCorpusMetadataValue] = ContentCorpusGrid.zone, + writer: Writer = .unattributed + ) { + self.init(record: record, start: start, end: end ?? start, metadata: metadata, device: nil, writer: writer, context: .plain) + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusInput.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusInput.swift new file mode 100644 index 000000000..f3f2705da --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusInput.swift @@ -0,0 +1,216 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation + + +/// One metadata value as HealthKit stores it: a string, an integer or floating-point number, or a Boolean. +/// +/// Encoded as a one-member object naming its kind, so `1`, `1.0` and `true` stay three different inputs. +enum ContentCorpusMetadataValue: Codable, Hashable, Sendable { + case string(String) + case integer(Int) + case double(Double) + case boolean(Bool) + + private enum CodingKeys: String, CodingKey { + case string + case integer + case double + case boolean + } + + init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + guard container.allKeys.count == 1, let key = container.allKeys.first else { + throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, debugDescription: "one kind per metadata value")) + } + self = switch key { + case .string: .string(try container.decode(String.self, forKey: key)) + case .integer: .integer(try container.decode(Int.self, forKey: key)) + case .double: .double(try container.decode(Double.self, forKey: key)) + case .boolean: .boolean(try container.decode(Bool.self, forKey: key)) + } + } + + func encode(to encoder: any Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + switch self { + case .string(let text): try container.encode(text, forKey: .string) + case .integer(let number): try container.encode(number, forKey: .integer) + case .double(let number): try container.encode(number, forKey: .double) + case .boolean(let flag): try container.encode(flag, forKey: .boolean) + } + } +} + + +/// One member of a correlation: its quantity type, value in `unit`, and the metadata it states itself. +struct ContentCorpusMember: Codable, Hashable, Sendable { + var type: String + var value: Double + var unit = "mmHg" + var metadata: [String: ContentCorpusMetadataValue] = [:] +} + + +/// One workout statistic, each reading in `unit`; an absent reading is one HealthKit did not report. +struct ContentCorpusStatistic: Codable, Hashable, Sendable { + var type: String + var unit: String + var sum: Double? + var average: Double? + var minimum: Double? + var maximum: Double? +} + + +/// An ECG's reading, voltages and correlated symptoms, as raw as HealthKit reports them. +struct ContentCorpusElectrocardiogram: Codable, Hashable, Sendable { + /// One voltage measurement; a nil voltage states no lead at all. + struct Voltage: Codable, Hashable, Sendable { + var offset: Double + var millivolts: Double? + } + + /// One correlated symptom sample, with its own UUID ordinal and the event context it converts under. + struct Symptom: Codable, Hashable, Sendable { + var type: String + var value: Int + var ordinal: UInt8 + } + + var classification: Int + var symptomsStatus: Int + var reportedCount: Int + var averageHeartRate: Double? + var samplingFrequency: Double? + var voltages: [Voltage] + var symptoms: [Symptom] = [] + /// How many symptom contexts the caller supplies, when that is not one per symptom. + var symptomContexts: Int? +} + + +/// One heartbeat of a series: seconds since the series start, and whether a gap preceded it. +struct ContentCorpusBeat: Codable, Hashable, Sendable { + var offset: Double + var gap: Bool +} + + +/// One route fix, `offset` seconds after the route starts; CoreLocation reports an unavailable reading as negative. +struct ContentCorpusLocation: Codable, Hashable, Sendable { + var offset: Double + var latitude: Double + var longitude: Double + var altitude: Double + var horizontalAccuracy: Double + var verticalAccuracy: Double + var course: Double + var courseAccuracy: Double + var speed: Double + var speedAccuracy: Double +} + + +/// The payload of one source record, by the HealthKit class that carries it. +enum ContentCorpusRecord: Codable, Hashable, Sendable { + case quantity(type: String, value: Double, unit: String) + /// A category sample with any raw value, admitted by HealthKit or not. + case category(type: String, value: Int) + case correlation(type: String, members: [ContentCorpusMember]) + case workout(activity: UInt, duration: Double, statistics: [ContentCorpusStatistic]) + case stateOfMind(kind: Int, valence: Double, labels: [Int], associations: [Int]) + case assessment(type: String, score: Int) + /// An ECG with its companion data, converted through the record entry point. + case electrocardiogram(reading: ContentCorpusElectrocardiogram) + case heartbeatSeries(beats: [ContentCorpusBeat]) + /// A route with its fixes; `disclosed` is the route-disclosure policy. + case workoutRoute(locations: [ContentCorpusLocation], disclosed: Bool) + /// A CDA document sample; a nil document is one fetched without its document data. + case cdaDocument(title: String, document: String?) + /// A clinical record; a nil resource is one HealthKit returned without its FHIR resource. + case clinicalRecord(type: String, fhirVersion: String, resource: String?) + /// A bare instance of `sampleClass` with no payload, passed to the plain sample entry point. + case bare(type: String, sampleClass: String) +} + + +/// One source record and the facts its sample carries besides its payload. +struct ContentCorpusSource: Codable, Hashable, Sendable { + /// The `HKDevice` the sample names. + enum Device: String, Codable, Sendable { + /// A watch with a per-unit token, so the graph carries a recording Device. + case watch + /// The same watch without one, whose omission is reported. + case watchWithoutUnitToken + } + + /// The `HKSourceRevision` the sample is attributed to. + enum Writer: String, Codable, Sendable { + /// No source at all, so the graph carries no writer. + case unattributed + /// A third-party application on its own phone. + case foreign + } + + /// The event context the record converts under. + enum Context: String, Codable, Sendable { + /// The suite's default context. + case plain + /// A gateway converter with one bundled study, so every output link a slot admits applies. + case linked + } + + var record: ContentCorpusRecord + /// The sample's start, in seconds since 1970. + var start: Double + /// The sample's end, in seconds since 1970. + var end: Double + var metadata: [String: ContentCorpusMetadataValue] + var device: Device? + var writer: Writer + var context: Context +} + + +/// One part of the public catalog surface. +enum ContentCorpusProjection: Codable, Hashable, Sendable { + /// A source type's inventory row, outputs and field dispositions. + case entry(type: String) + /// Every published unit binding, in order. + case unitBindings + /// Both unit lookups for each spelling. + case unitSpellings(spellings: [String]) + /// The sample an Observation, given as its JSON, projects back to. + case reverse(observation: String) +} + + +/// One corpus line's key and input. +struct ContentCorpusVector: Hashable, Sendable { + let id: String + let input: ContentCorpusInput +} + + +/// What one content-corpus vector feeds the converter, stated as data so the corpus rebuilds every record +/// from the checked-in file alone, through `StoredSampleFixtures`, whatever code produced the line. +enum ContentCorpusInput: Codable, Hashable, Sendable { + /// Convert one source record. + case convert(source: ContentCorpusSource) + /// Name the outputs a deletion of a record of this type retracts. + case retract(type: String) + /// Project one part of the public catalog. + case catalog(projection: ContentCorpusProjection) +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusRecorder.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusRecorder.swift new file mode 100644 index 000000000..5117275c1 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusRecorder.swift @@ -0,0 +1,202 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +@testable import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit +import ModelsR4 + + +/// Runs one corpus vector through the converter's public entry points and renders what came out as JSON tokens. +/// +/// A conversion renders, per graph, the output resources exactly as the wire carries them and the warnings in +/// order; a refusal renders as its registry code, location and Swift error, and a policy omission as such. The rest +/// of the envelope (Provenance, Devices) stays out: the goldens pin it. +/// +/// Converted Observations are not projected back here: `Observation.healthKitSample()` builds the sample through +/// HealthKit's initializers, which raise an uncatchable exception for an instant HealthKit refuses (after 4000, or +/// shorter than a type's minimum duration). The `reverse/` vectors project curated Observations instead. +enum ContentCorpusRecorder { + /// What converting one source record produced. + enum Outcome { + case converted(HealthKitConversionSet) + case omitted + case refused(HealthKitConversionError) + } + + /// The event sequence every vector converts under; an ECG's symptoms take the sequences after it. + static let sequence: UInt64 = 300 + + /// The output resources a graph's content layer produces; every other entry is envelope. + private static let outputResourceTypes: Set = [ResourceType.observation.rawValue, ResourceType.documentReference.rawValue] + + /// The corpus line's output for `input`; a vector the fixtures cannot rebuild throws instead. + static func output(for input: ContentCorpusInput) throws -> LosslessJSONValue { + switch input { + case .convert(let source): try render(try outcome(of: source)) + case .retract(let type): try retraction(of: type) + case .catalog(let projection): try ContentCorpusCatalog.projection(projection) + } + } + + /// Converts `source` through the entry point its record takes. + static func outcome(of source: ContentCorpusSource) throws -> Outcome { + let context = try context(for: source) + let converter = HealthKitConverter() + switch source.record { + case .electrocardiogram(let reading): + let record = try ContentCorpusSamples.electrocardiogram(source, reading: reading) + let symptomContexts = try (0..<(reading.symptomContexts ?? reading.symptoms.count)).map { index in + try GoldenFixtures.context(sequence: sequence + 1 + UInt64(index)) + } + return capture { () throws(HealthKitConversionError) in + try converter.convert(record, context: context, symptomContexts: symptomContexts) + } + case .heartbeatSeries(let beats): + let record = try ContentCorpusSamples.heartbeatSeries(source, beats: beats) + return capture { () throws(HealthKitConversionError) in try converter.convert(record, context: context) } + case .workoutRoute(let locations, _): + let record = try ContentCorpusSamples.workoutRoute(source, locations: locations) + do { + return try converter.convert(record, context: context).map(Outcome.converted) ?? .omitted + } catch { + return .refused(error) + } + default: + let sample = try ContentCorpusSamples.sample(source) + return capture { () throws(HealthKitConversionError) in try converter.convert(sample, context: context) } + } + } + + static func render(_ outcome: Outcome) throws -> LosslessJSONValue { + switch outcome { + case .converted(let set): + .object(["graphs": .array(try set.all.map(graph))]) + case .omitted: + .object(["omitted": .boolean(true)]) + case .refused(let error): + refusal(error) + } + } + + /// The suite's fixed context, under a gateway converter with one study when the vector asks for every link. + private static func context(for source: ContentCorpusSource) throws -> HealthKitConversionContext { + var inputs = GoldenFixtures.Inputs() + if source.context == .linked { + inputs.converterRole = .gateway + inputs.studies = [.test("study-a")] + } + if case .workoutRoute(_, disclosed: true) = source.record { + inputs.options.routeDisclosure = .authorized + } + return try GoldenFixtures.context(sequence: sequence, inputs) + } + + private static func capture(_ convert: () throws(HealthKitConversionError) -> HealthKitConversionSet) -> Outcome { + do { + return .converted(try convert()) + } catch { + return .refused(error) + } + } + + private static func refusal(_ error: HealthKitConversionError) -> LosslessJSONValue { + let refusal = LosslessJSONValue.object([ + "code": .string(error.diagnostic.code), + "location": .string(error.diagnostic.location), + "error": .string(String(describing: error)) + ]) + return .object(["refused": refusal]) + } + + /// One graph's output resources as its wire bytes state them, and its warnings. + private static func graph(_ conversion: HealthKitConversion) throws -> LosslessJSONValue { + let bundle = try LosslessJSONValue(parsing: conversion.graph.json) + let outputs = (bundle["entry"]?.elements ?? []).compactMap { $0["resource"] }.filter { resource in + outputResourceTypes.contains(resource["resourceType"]?.text ?? "") + } + return .object([ + "outputs": .array(outputs), + "warnings": .array(GoldenOutput(conversion).renderedWarnings.map(LosslessJSONValue.string)) + ]) + } + + /// The deletion of a record of `type`: the targets it retracts, or why it retracts none. + private static func retraction(of type: String) throws -> LosslessJSONValue { + guard let sourceType = HealthKitSourceType(rawValue: type) else { + throw ContentCorpusSamples.RebuildError.unknownType(type) + } + let context = try GoldenFixtures.context(sequence: sequence) + let record = HealthKitSourceRecord(uuid: ContentCorpusSamples.uuid, type: sourceType) + do { + let targets = try HealthKitConverter().retractionTargets(for: record, context: context).map { target in + LosslessJSONValue.object([ + "identifier": .string(target.identifier.identifier.value), + "identifierRole": .string(target.identifier.role.rawValue), + "resourceType": .string(target.resourceType.rawValue), + "role": .string(target.role.rawValue) + ]) + } + return .object(["targets": .array(targets)]) + } catch { + return refusal(error) + } + } + + /// The sample `observation` projects back to, or why it does not. + static func reverse(_ observation: Observation) -> LosslessJSONValue { + do { + return sample(try observation.healthKitSample()) + } catch { + let refusal = LosslessJSONValue.object([ + "code": .string(error.diagnostic.code), + "error": .string(String(describing: error)) + ]) + return .object(["refused": refusal]) + } + } + + /// A projected sample's type, interval, metadata, value and members, every number as its shortest text. + private static func sample(_ sample: HKSample) -> LosslessJSONValue { + var members: [String: LosslessJSONValue] = [ + "type": .string(sample.sampleType.identifier), + "start": .string(String(sample.startDate.timeIntervalSince1970)), + "end": .string(String(sample.endDate.timeIntervalSince1970)), + "metadata": .object((sample.metadata ?? [:]).mapValues { .string(metadataText($0)) }) + ] + if let quantitySample = sample as? HKQuantitySample { + members["quantity"] = .string(quantityText(quantitySample.quantity)) + } + if let correlation = sample as? HKCorrelation { + let objects = correlation.objects.map(Self.sample).sorted { $0.canonicalText < $1.canonicalText } + members["objects"] = .array(objects) + } + return .object(members) + } + + private static func metadataText(_ value: Any) -> String { + switch value { + case let text as String: text + case let number as NSNumber: number.stringValue + default: String(describing: value) + } + } + + /// A quantity in the unit it was created with, which HealthKit keeps but does not publish. + private static func quantityText(_ quantity: HKQuantity) -> String { + guard let unit = quantity.value(forKey: "unit") as? HKUnit else { + return quantity.description + } + return "\(String(quantity.doubleValue(for: unit))) \(unit.unitString)" + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusSamples+Records.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusSamples+Records.swift new file mode 100644 index 000000000..66cf091a1 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusSamples+Records.swift @@ -0,0 +1,252 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import CoreLocation +import Foundation +@testable import GroveHealthKitFHIR +import HealthKit + + +/// The clinical samples, which watchOS does not have. +enum ContentCorpusClinicalSamples { + #if os(watchOS) + static func sample(_ record: ContentCorpusRecord, shape: StoredSampleFixtures.SeriesShape) throws -> HKSample { + throw ContentCorpusSamples.RebuildError.unknownClass("HKClinicalRecord") + } + #else + static func sample(_ record: ContentCorpusRecord, shape: StoredSampleFixtures.SeriesShape) throws -> HKSample { + switch record { + case let .cdaDocument(title, document): + return try cdaDocument(title: title, document: document, shape: shape) + case let .clinicalRecord(type, fhirVersion, resource): + return try clinicalRecord(type: type, fhirVersion: fhirVersion, resource: resource, shape: shape) + default: + throw ContentCorpusSamples.RebuildError.notASample + } + } + + /// A CDA sample as an `HKDocumentQuery` returns it, with its document data, or without when `document` is nil. + private static func cdaDocument(title: String, document: String?, shape: StoredSampleFixtures.SeriesShape) throws -> HKSample { + guard let documentType = HKObjectType.documentType(forIdentifier: .CDA) else { + throw ContentCorpusSamples.RebuildError.unknownType(HKDocumentTypeIdentifier.CDA.rawValue) + } + let sample = try StoredSampleFixtures.seriesSample(HKCDADocumentSample.self, sampleType: documentType, shape: shape) + guard let document else { + return sample + } + let content = try StoredSampleFixtures.allocate(HKCDADocument.self) + try StoredSampleFixtures.write(Data(document.utf8), to: "internalDocumentData", of: content) + try StoredSampleFixtures.write(title, to: "title", of: content) + try StoredSampleFixtures.write(content, to: "document", of: sample) + guard sample.document?.documentData == Data(document.utf8), sample.document?.title == title else { + throw ContentCorpusSamples.RebuildError.notHonored("CDA document") + } + return sample + } + + /// A clinical record carrying `resource` under `fhirVersion`, or no FHIR resource at all when it is nil. + private static func clinicalRecord( + type: String, + fhirVersion: String, + resource: String?, + shape: StoredSampleFixtures.SeriesShape + ) throws -> HKSample { + guard let clinicalType = HKObjectType.clinicalType(forIdentifier: HKClinicalTypeIdentifier(rawValue: type)) else { + throw ContentCorpusSamples.RebuildError.unknownType(type) + } + let record = try StoredSampleFixtures.seriesSample(HKClinicalRecord.self, sampleType: clinicalType, shape: shape) + guard let resource else { + return record + } + let content = try StoredSampleFixtures.allocate(HKFHIRResource.self) + try StoredSampleFixtures.write(Data(resource.utf8), to: "data", of: content) + try StoredSampleFixtures.write(try HKFHIRVersion(fromVersionString: fhirVersion), to: "FHIRVersion", of: content) + try StoredSampleFixtures.write(content, to: "FHIRResource", of: record) + guard record.fhirResource?.data == Data(resource.utf8) else { + throw ContentCorpusSamples.RebuildError.notHonored("FHIR resource") + } + return record + } + #endif +} + + +extension ContentCorpusSamples { + /// A workout, State of Mind or scored assessment stating exactly the vector's payload. + static func reflection(_ record: ContentCorpusRecord, shape: StoredSampleFixtures.SeriesShape) throws -> HKSample { + switch record { + case let .workout(activity, duration, statistics): + try workout(activity: activity, duration: duration, statistics: statistics, shape: shape) + case let .stateOfMind(kind, valence, labels, associations): + try stateOfMind(kind: kind, valence: valence, labels: labels, associations: associations, shape: shape) + case let .assessment(type, score): + try assessment(type: type, score: score, shape: shape) + default: + throw RebuildError.notASample + } + } + + /// The ECG record the record entry point takes; each symptom carries the ECG's interval and the default zone. + static func electrocardiogram(_ source: ContentCorpusSource, reading: ContentCorpusElectrocardiogram) throws -> HealthKitECGRecord { + let beatsPerMinute = HKUnit.count().unitDivided(by: .minute()) + let ecg = try StoredSampleFixtures.electrocardiogram( + shape: shape(source), + reading: StoredElectrocardiogram.Reading( + classification: try rawEnumeration(reading.classification, HKElectrocardiogram.Classification.init(rawValue:)), + symptomsStatus: try rawEnumeration(reading.symptomsStatus, HKElectrocardiogram.SymptomsStatus.init(rawValue:)), + numberOfVoltageMeasurements: reading.reportedCount, + averageHeartRate: reading.averageHeartRate.map { HKQuantity(unit: beatsPerMinute, doubleValue: $0) }, + samplingFrequency: reading.samplingFrequency.map { HKQuantity(unit: .hertz(), doubleValue: $0) } + ) + ) + var symptomSource = source + symptomSource.device = nil + symptomSource.writer = .unattributed + symptomSource.metadata = [HKMetadataKeyTimeZone: .string(GoldenFixtures.timeZone)] + return HealthKitECGRecord( + electrocardiogram: ecg, + voltageMeasurements: try reading.voltages.map { voltage in + try StoredSampleFixtures.voltageMeasurement(offset: voltage.offset, millivolts: voltage.millivolts) + }, + correlatedSymptoms: try reading.symptoms.map { symptom in + try category(type: symptom.type, value: symptom.value, shape: shape(symptomSource, uuid: GoldenFixtures.uuid(symptom.ordinal))) + } + ) + } + + static func heartbeatSeries(_ source: ContentCorpusSource, beats: [ContentCorpusBeat]) throws -> HealthKitHeartbeatSeriesRecord { + HealthKitHeartbeatSeriesRecord( + series: try StoredSampleFixtures.seriesSample(HKHeartbeatSeriesSample.self, sampleType: HKSeriesType.heartbeat(), shape: shape(source)), + heartbeats: beats.map { HealthKitHeartbeat(timeSinceSeriesStart: $0.offset, precededByGap: $0.gap) } + ) + } + + static func workoutRoute(_ source: ContentCorpusSource, locations: [ContentCorpusLocation]) throws -> HealthKitWorkoutRouteRecord { + let start = Date(timeIntervalSince1970: source.start) + return HealthKitWorkoutRouteRecord( + route: try StoredSampleFixtures.seriesSample(HKWorkoutRoute.self, sampleType: HKSeriesType.workoutRoute(), shape: shape(source)), + locations: locations.map { fix in + CLLocation( + coordinate: CLLocationCoordinate2D(latitude: fix.latitude, longitude: fix.longitude), + altitude: fix.altitude, + horizontalAccuracy: fix.horizontalAccuracy, + verticalAccuracy: fix.verticalAccuracy, + course: fix.course, + courseAccuracy: fix.courseAccuracy, + speed: fix.speed, + speedAccuracy: fix.speedAccuracy, + timestamp: start.addingTimeInterval(fix.offset) + ) + } + ) + } + + /// An imported enumeration's case for any raw value, known to this SDK or not. + private static func rawEnumeration(_ raw: Int, _ make: (Int) -> Value?) throws -> Value { + guard let value = make(raw) else { + throw RebuildError.notHonored("raw value \(raw)") + } + return value + } + + /// A workout of any activity raw value, duration and statistics; HealthKit computes statistics only while + /// recording one, so they are written into its primary activity. + private static func workout( + activity: UInt, + duration: Double, + statistics: [ContentCorpusStatistic], + shape: StoredSampleFixtures.SeriesShape + ) throws -> HKWorkout { + let workout = HKWorkout(activityType: .running, start: GoldenFixtures.sampleStart, end: GoldenFixtures.sampleStart.addingTimeInterval(60)) + try StoredSampleFixtures.write(NSNumber(value: activity), to: "workoutActivityType", of: workout) + try StoredSampleFixtures.write(NSNumber(value: duration), to: "duration", of: workout) + guard let primary = workout.value(forKey: "primaryActivity") as? NSObject, + let byType = primary.value(forKey: "statisticsPerType") as? NSMutableDictionary else { + throw RebuildError.notHonored("workout statistics") + } + for statistic in statistics { + let quantityType = try workoutStatisticType(statistic.type) + byType[quantityType] = try workoutStatistic(statistic, type: quantityType) + } + guard workout.workoutActivityType.rawValue == activity, workout.duration.bitPattern == duration.bitPattern, + workout.allStatistics.count == statistics.count else { + throw RebuildError.notHonored("workout activity, duration or statistics") + } + return try StoredSampleFixtures.restated(workout, shape: shape) + } + + private static func workoutStatisticType(_ type: String) throws -> HKQuantityType { + guard let quantityType = HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier(rawValue: type)) else { + throw RebuildError.unknownType(type) + } + return quantityType + } + + /// One statistics object with only the readings the vector states. + private static func workoutStatistic(_ statistic: ContentCorpusStatistic, type: HKQuantityType) throws -> NSObject { + let unit = HKUnit(from: statistic.unit) + guard type.is(compatibleWith: unit) else { + throw RebuildError.incompatibleUnit(type: statistic.type, unit: statistic.unit) + } + let object = try StoredSampleFixtures.allocate(HKStatistics.self) + try StoredSampleFixtures.write(type, to: "dataType", of: object) + let readings: [(key: String, value: Double?)] = [ + ("sumQuantity", statistic.sum), ("averageQuantity", statistic.average), + ("minimumQuantity", statistic.minimum), ("maximumQuantity", statistic.maximum) + ] + for reading in readings { + try StoredSampleFixtures.write(reading.value.map { HKQuantity(unit: unit, doubleValue: $0) }, to: reading.key, of: object) + } + return object + } + + /// A reflection of any kind and labels, which HealthKit refuses at creation unless it knows them. + private static func stateOfMind( + kind: Int, + valence: Double, + labels: [Int], + associations: [Int], + shape: StoredSampleFixtures.SeriesShape + ) throws -> HKStateOfMind { + // HealthKit classifies the valence when it is read and traps outside -1...1, so no vector states one. + guard (-1...1).contains(valence) else { + throw RebuildError.notHonored("valence \(valence)") + } + let reflection = HKStateOfMind(date: GoldenFixtures.sampleStart, kind: .momentaryEmotion, valence: 0, labels: [], associations: []) + try StoredSampleFixtures.write(NSNumber(value: kind), to: "kind", of: reflection) + try StoredSampleFixtures.write(NSNumber(value: valence), to: "valence", of: reflection) + try StoredSampleFixtures.write(labels.map { NSNumber(value: $0) }, to: "labels", of: reflection) + try StoredSampleFixtures.write(associations.map { NSNumber(value: $0) }, to: "associations", of: reflection) + guard reflection.kind.rawValue == kind, reflection.valence == valence, + reflection.labels.map(\.rawValue) == labels, reflection.associations.map(\.rawValue) == associations else { + throw RebuildError.notHonored("State of Mind") + } + return try StoredSampleFixtures.restated(reflection, shape: shape) + } + + /// A GAD-7 or PHQ-9 assessment stating any score. + private static func assessment(type: String, score: Int, shape: StoredSampleFixtures.SeriesShape) throws -> HKScoredAssessment { + let assessment: HKScoredAssessment = switch type { + case HKScoredAssessmentTypeIdentifier.GAD7.rawValue: + HKGAD7Assessment(date: GoldenFixtures.sampleStart, answers: Array(repeating: .notAtAll, count: 7)) + case HKScoredAssessmentTypeIdentifier.PHQ9.rawValue: + HKPHQ9Assessment(date: GoldenFixtures.sampleStart, answers: Array(repeating: .notAtAll, count: 9)) + default: + throw RebuildError.unknownType(type) + } + try StoredSampleFixtures.write(NSNumber(value: score), to: "score", of: assessment) + guard assessment.score == score else { + throw RebuildError.notHonored("assessment score") + } + return try StoredSampleFixtures.restated(assessment, shape: shape) + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusSamples.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusSamples.swift new file mode 100644 index 000000000..568a7afb4 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusSamples.swift @@ -0,0 +1,200 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import CoreLocation +import Foundation +@testable import GroveHealthKitFHIR +import HealthKit + + +/// Rebuilds a corpus vector's records the way HealthKit hands them back, through `StoredSampleFixtures`. +/// +/// Each sample starts from its class's public initializer with values HealthKit admits, or as a bare instance +/// where the class has none or would refuse the vector, and is then restated with the vector's exact facts. +enum ContentCorpusSamples { + enum RebuildError: Error, CustomStringConvertible { + case unknownType(String) + case unknownClass(String) + case incompatibleUnit(type: String, unit: String) + case notHonored(String) + case notASample + + var description: String { + switch self { + case .unknownType(let type): "this HealthKit does not know \(type)" + case .unknownClass(let name): "this HealthKit has no class \(name)" + case let .incompatibleUnit(type, unit): "\(unit) does not measure \(type)" + case .notHonored(let fact): "HealthKit no longer reads back the \(fact) the corpus writes" + case .notASample: "the record converts through its own entry point" + } + } + } + + /// The UUID of every vector's record; members and symptoms take their own ordinals. + static let uuid = GoldenFixtures.uuid(0xC0) + + /// The bare classes the plain entry point is fed, by the sample type they carry. + private static let bareSampleTypes: [String: HKSampleType] = [ + HKObjectType.audiogramSampleType().identifier: HKObjectType.audiogramSampleType(), + HKObjectType.visionPrescriptionType().identifier: HKObjectType.visionPrescriptionType(), + HKObjectType.medicationDoseEventType().identifier: HKObjectType.medicationDoseEventType(), + HKObjectType.electrocardiogramType().identifier: HKObjectType.electrocardiogramType(), + HKSeriesType.heartbeat().identifier: HKSeriesType.heartbeat(), + HKSeriesType.workoutRoute().identifier: HKSeriesType.workoutRoute() + ] + + /// Every fact of `source` except its payload, under `uuid`. + static func shape(_ source: ContentCorpusSource, uuid: UUID = uuid) -> StoredSampleFixtures.SeriesShape { + StoredSampleFixtures.SeriesShape( + uuid: uuid, + start: Date(timeIntervalSince1970: source.start), + end: Date(timeIntervalSince1970: source.end), + device: source.device.map { $0 == .watch ? GoldenFixtures.watch : GoldenFixtures.watchWithoutUnitToken }, + metadata: source.metadata.isEmpty ? nil : source.metadata.mapValues(\.value), + writer: source.writer == .foreign ? GoldenFixtures.foreignWriter : .unattributed + ) + } + + /// The sample a vector feeds the plain sample entry point. + static func sample(_ source: ContentCorpusSource) throws -> HKSample { + let shape = shape(source) + switch source.record { + case let .quantity(type, value, unit): + return try quantity(type: type, value: value, unit: unit, shape: shape) + case let .category(type, value): + return try category(type: type, value: value, shape: shape) + case let .correlation(type, members): + return try correlation(type: type, members: members, shape: shape) + case let .bare(type, sampleClass): + return try bare(type: type, sampleClass: sampleClass, shape: shape) + case .workout, .stateOfMind, .assessment: + return try reflection(source.record, shape: shape) + case .cdaDocument, .clinicalRecord: + return try ContentCorpusClinicalSamples.sample(source.record, shape: shape) + case .electrocardiogram, .heartbeatSeries, .workoutRoute: + throw RebuildError.notASample + } + } + + /// A quantity sample of any value over any interval: HealthKit validates both per type at creation, so the + /// sample is a bare instance of the class its initializer would have chosen. + static func quantity(type: String, value: Double, unit: String, shape: StoredSampleFixtures.SeriesShape) throws -> HKQuantitySample { + guard let quantityType = HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier(rawValue: type)) else { + throw RebuildError.unknownType(type) + } + let healthKitUnit = HKUnit(from: unit) + guard quantityType.is(compatibleWith: healthKitUnit) else { + throw RebuildError.incompatibleUnit(type: type, unit: unit) + } + let sampleClass: HKQuantitySample.Type = quantityType.aggregationStyle == .cumulative + ? HKCumulativeQuantitySample.self + : HKDiscreteQuantitySample.self + let sample = try StoredSampleFixtures.seriesSample(sampleClass, sampleType: quantityType, shape: shape) + try StoredSampleFixtures.write(HKQuantity(unit: healthKitUnit, doubleValue: value), to: "quantity", of: sample) + try StoredSampleFixtures.write(NSNumber(value: 1), to: "count", of: sample) + let stated = sample.quantity.doubleValue(for: healthKitUnit) + guard stated == value || (stated.isNaN && value.isNaN) else { + throw RebuildError.notHonored("quantity") + } + return sample + } + + /// A category sample with any raw value: HealthKit refuses an unadmitted one at creation, so the sample is bare. + static func category(type: String, value: Int, shape: StoredSampleFixtures.SeriesShape) throws -> HKCategorySample { + guard let categoryType = HKObjectType.categoryType(forIdentifier: HKCategoryTypeIdentifier(rawValue: type)) else { + throw RebuildError.unknownType(type) + } + let sample = try StoredSampleFixtures.seriesSample(HKCategorySample.self, sampleType: categoryType, shape: shape) + try StoredSampleFixtures.write(NSNumber(value: value), to: "value", of: sample) + guard sample.value == value else { + throw RebuildError.notHonored("category value") + } + return sample + } + + /// A correlation with exactly `members`, which HealthKit's initializer would refuse unless it is one valid pair. + private static func correlation( + type: String, + members: [ContentCorpusMember], + shape: StoredSampleFixtures.SeriesShape + ) throws -> HKCorrelation { + let identifier = HKCorrelationTypeIdentifier(rawValue: type) + guard let correlationType = HKObjectType.correlationType(forIdentifier: identifier) else { + throw RebuildError.unknownType(type) + } + let correlation = HKCorrelation( + type: correlationType, + start: GoldenFixtures.sampleStart, + end: GoldenFixtures.sampleStart, + objects: try placeholders(for: identifier) + ) + let objects = NSMutableDictionary() + for (index, member) in members.enumerated() { + var memberShape = shape + memberShape.uuid = GoldenFixtures.uuid(0xD0 + UInt8(index)) + memberShape.device = nil + memberShape.metadata = member.metadata.isEmpty ? nil : member.metadata.mapValues(\.value) + memberShape.writer = .unattributed + let sample = try quantity(type: member.type, value: member.value, unit: member.unit, shape: memberShape) + let group = objects[sample.sampleType] as? NSMutableSet ?? NSMutableSet() + group.add(sample) + objects[sample.sampleType] = group + } + try StoredSampleFixtures.write(objects, to: "objects", of: correlation) + guard correlation.objects.count == members.count else { + throw RebuildError.notHonored("correlation objects") + } + return try StoredSampleFixtures.restated(correlation, shape: shape) + } + + /// Objects the correlation's initializer admits: a blood-pressure pair, or one food entry. They carry no writer, + /// the only attribution the initializer accepts for its objects, and are replaced by the vector's members. + private static func placeholders(for identifier: HKCorrelationTypeIdentifier) throws -> Set { + let pressure = HKUnit.millimeterOfMercury() + let objects: [(HKQuantityTypeIdentifier, HKQuantity)] = identifier == .bloodPressure + ? [(.bloodPressureSystolic, HKQuantity(unit: pressure, doubleValue: 120)), (.bloodPressureDiastolic, HKQuantity(unit: pressure, doubleValue: 80))] + : [(.dietaryEnergyConsumed, HKQuantity(unit: .kilocalorie(), doubleValue: 1))] + return Set(try objects.enumerated().map { index, object in + let sample = HKQuantitySample( + type: HKQuantityType(object.0), + quantity: object.1, + start: GoldenFixtures.sampleStart, + end: GoldenFixtures.sampleStart + ) + return try StoredSampleFixtures.stored(sample, uuid: GoldenFixtures.uuid(0xCE + UInt8(index))) + }) + } + + /// A bare instance of a class the corpus feeds the plain entry point without a payload. + private static func bare(type: String, sampleClass: String, shape: StoredSampleFixtures.SeriesShape) throws -> HKSample { + guard let sampleType = bareSampleTypes[type] else { + throw RebuildError.unknownType(type) + } + guard let healthKitClass = NSClassFromString(sampleClass) as? HKSample.Type else { + throw RebuildError.unknownClass(sampleClass) + } + return try StoredSampleFixtures.seriesSample(healthKitClass, sampleType: sampleType, shape: shape) + } +} + + +extension ContentCorpusMetadataValue { + /// The value HealthKit keeps, bridged to the Foundation object it stores. + var value: any Sendable { + switch self { + case .string(let text): text + case .integer(let number): number + case .double(let number): number + case .boolean(let flag): flag + } + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusStore.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusStore.swift new file mode 100644 index 000000000..ca631cc12 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusStore.swift @@ -0,0 +1,189 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +@testable import GroveFHIRContract + + +/// Where the content corpus lives, how its lines read and print, and where a regeneration writes. +/// +/// The corpus is `Resources/ContentCorpus/content-corpus.jsonl`: one line per vector, an object with the vector's +/// `id`, its `input` and its `output`, printed compactly with members sorted and output number lexemes kept. It is +/// regenerated exactly like the goldens, OUTSIDE the checkout: with `GROVE_GOLDEN_OUTPUT_DIR` set (under +/// `xcodebuild`, `TEST_RUNNER_GROVE_GOLDEN_OUTPUT_DIR`), the suite writes `content-corpus.jsonl` there, to be +/// copied in afterwards, and only in a commit whose diff is exactly the enumerated change of one fix. +enum ContentCorpusStore { + /// One checked-in line: its key, its input, and the output it pins. + struct Line { + let id: String + let input: ContentCorpusInput + let output: LosslessJSONValue + } + + struct MalformedLine: Error, CustomStringConvertible { + let number: Int + + var description: String { + "content-corpus.jsonl line \(number) is not an object with an id, an input and an output" + } + } + + struct MissingCorpus: Error, CustomStringConvertible { + var description: String { + "No content-corpus.jsonl is checked in; regenerate with GROVE_GOLDEN_OUTPUT_DIR and copy it into Resources/ContentCorpus" + } + } + + /// What a line states besides its output; read by Foundation, which keeps every string exactly. + private struct Key: Decodable { + let id: String + let input: ContentCorpusInput + } + + static let name = "content-corpus" + static let fileExtension = "jsonl" + + static let outputDirectory: URL? = ProcessInfo.processInfo.environment["GROVE_GOLDEN_OUTPUT_DIR"] + .flatMap { $0.isEmpty ? nil : URL(fileURLWithPath: $0, isDirectory: true) } + + static var isGenerating: Bool { outputDirectory != nil } + + /// Sorted members, unescaped slashes, and non-finite inputs as strings, since JSON has no literal for them. + private static var encoder: JSONEncoder { + let encoder = JSONEncoder() + encoder.outputFormatting = [.sortedKeys, .withoutEscapingSlashes] + encoder.nonConformingFloatEncodingStrategy = .convertToString(positiveInfinity: "Infinity", negativeInfinity: "-Infinity", nan: "NaN") + return encoder + } + + private static var decoder: JSONDecoder { + let decoder = JSONDecoder() + decoder.nonConformingFloatDecodingStrategy = .convertFromString(positiveInfinity: "Infinity", negativeInfinity: "-Infinity", nan: "NaN") + return decoder + } + + /// The checked-in corpus, whichever way the build system laid the resources out. + static func checkedIn() throws -> Data { + guard let url = Bundle.module.url(forResource: name, withExtension: fileExtension, subdirectory: "ContentCorpus") + ?? Bundle.module.url(forResource: name, withExtension: fileExtension) else { + throw MissingCorpus() + } + return try Data(contentsOf: url) + } + + /// Reads the lines of `data` whose zero-based number leaves `shard.index` modulo `shard.count`, one at a time, + /// so the corpus is never held as parsed tokens all at once. + static func forEachLine(in data: Data, shard: (index: Int, count: Int) = (0, 1), _ body: (Line) throws -> Void) throws { + for (number, slice) in data.split(separator: UInt8(ascii: "\n"), omittingEmptySubsequences: true).enumerated() + where number % shard.count == shard.index { + try autoreleasepool { + try body(try line(Data(slice), number: number + 1)) + } + } + } + + /// Every line's id and input, in order, leaving the outputs unread. + static func vectors(in data: Data) throws -> [ContentCorpusVector] { + try data.split(separator: UInt8(ascii: "\n"), omittingEmptySubsequences: true).enumerated().map { number, slice in + guard let key = try? decoder.decode(Key.self, from: Data(slice)) else { + throw MalformedLine(number: number + 1) + } + return ContentCorpusVector(id: key.id, input: key.input) + } + } + + /// The input as the corpus prints it; two inputs compare by this text, so a NaN equals itself. + static func inputText(_ input: ContentCorpusInput) throws -> String { + String(decoding: try encoder.encode(input), as: UTF8.self) + } + + /// The line a vector and its output print as. + static func line(_ vector: ContentCorpusVector, output: LosslessJSONValue) throws -> String { + let id = String(decoding: try encoder.encode(vector.id), as: UTF8.self) + let input = try inputText(vector.input) + return #"{"id":\#(id),"input":\#(input),"output":\#(output.canonicalText)}"# + } + + /// Writes the regenerated corpus into the output directory. + static func write(_ lines: [String]) throws { + guard let directory = outputDirectory else { + return + } + try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true) + let text = lines.map { $0 + "\n" }.joined() + try Data(text.utf8).write(to: directory.appendingPathComponent("\(name).\(fileExtension)")) + } + + private static func line(_ data: Data, number: Int) throws -> Line { + guard let key = try? decoder.decode(Key.self, from: data), + let output = (try? LosslessJSONValue(parsing: data))?["output"] else { + throw MalformedLine(number: number) + } + return Line(id: key.id, input: key.input, output: output) + } +} + + +extension LosslessJSONValue { + /// Compact JSON with members sorted by key and every number lexeme kept as read: two values print alike exactly + /// when their tokens are equal, so a corpus line diffs by content. + var canonicalText: String { + var text = "" + append(to: &text) + return text + } + + private static func append(_ string: String, to text: inout String) { + text.append("\"") + for scalar in string.unicodeScalars { + switch scalar { + case "\"": text.append("\\\"") + case "\\": text.append("\\\\") + case "\n": text.append("\\n") + case "\r": text.append("\\r") + case "\t": text.append("\\t") + case _ where scalar.value < 0x20: text.append(String(format: "\\u%04x", scalar.value)) + default: text.unicodeScalars.append(scalar) + } + } + text.append("\"") + } + + private func append(to text: inout String) { + switch self { + case .object(let members): + text.append("{") + for (index, key) in members.keys.sorted().enumerated() { + text.append(index == 0 ? "" : ",") + Self.append(key, to: &text) + text.append(":") + members[key]?.append(to: &text) + } + text.append("}") + case .array(let elements): + text.append("[") + for (index, element) in elements.enumerated() { + text.append(index == 0 ? "" : ",") + element.append(to: &text) + } + text.append("]") + case .string(let string): + Self.append(string, to: &text) + case .number(let lexeme): + text.append(lexeme) + case .boolean(let flag): + text.append(flag ? "true" : "false") + case .null: + text.append("null") + } + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusTests.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusTests.swift new file mode 100644 index 000000000..d95266eeb --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusTests.swift @@ -0,0 +1,102 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +@testable import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit +import Testing + + +/// The content corpus, oracle O2 of the HealthKit content rewrite: every checked-in vector converts to exactly the +/// tokens its line pins, the grid that generates the corpus still states exactly the checked-in inputs, and every +/// output a conversion emits is one the catalog names for its source type. +/// +/// The corpus was recorded from the content builders the rewrite replaces, so any change in content output fails +/// here with the vector and the first differing path. A deliberate change regenerates the corpus (see +/// `ContentCorpusStore`) in the one commit whose enumerated diff it is. +@Suite +struct ContentCorpusTests { + /// The corpus splits into this many shards, which run in parallel. + static let shards = 8 + + /// Whether this platform can rebuild a vector: watchOS has no clinical records or CDA documents. + static func isAvailableHere(_ id: String) -> Bool { + #if os(watchOS) + !id.hasPrefix("cda/") && !id.hasPrefix("clinical/") + #else + true + #endif + } + + @Test(.enabled(if: !ContentCorpusStore.isGenerating), arguments: 0.. 0, "shard \(shard) of the corpus is empty") + #expect(drifted.isEmpty, "\(drifted.count) vectors drifted from the corpus: \(drifted.prefix(25))") + #expect(uncataloged.isEmpty, "\(uncataloged.count) emitted outputs the catalog does not name: \(uncataloged.prefix(25))") + } + + /// The generator and the file agree line for line, and ids are unique. + @Test(.enabled(if: !ContentCorpusStore.isGenerating)) + func gridIsTheCheckedInCorpus() throws { + let grid = ContentCorpusGrid.vectors.filter { Self.isAvailableHere($0.id) } + let checkedIn = try ContentCorpusStore.vectors(in: ContentCorpusStore.checkedIn()).filter { Self.isAvailableHere($0.id) } + let ids = grid.map(\.id) + let stray = Set(checkedIn.map(\.id)).subtracting(ids).sorted().prefix(10) + let missing = Set(ids).subtracting(checkedIn.map(\.id)).sorted().prefix(10) + #expect(Set(ids).count == ids.count, "the grid names a vector twice") + #expect(checkedIn.map(\.id) == ids, "lines without a vector: \(stray); vectors without a line: \(missing)") + let changed = try zip(grid, checkedIn).compactMap { vector, line in + try ContentCorpusStore.inputText(vector.input) == ContentCorpusStore.inputText(line.input) ? nil : vector.id + } + #expect(changed.isEmpty, "the grid states other inputs than the corpus: \(changed.prefix(10))") + } + + /// With `GROVE_GOLDEN_OUTPUT_DIR` set, records every vector twice, requires identical tokens, and writes the + /// corpus there. Regenerate on macOS (the gate's platform), never on watchOS, whose grid has no clinical documents. + @Test(.enabled(if: ContentCorpusStore.isGenerating)) + func corpusRegenerates() throws { + var lines: [String] = [] + var nondeterministic: [String] = [] + for vector in ContentCorpusGrid.vectors { + try autoreleasepool { + let output = try ContentCorpusRecorder.output(for: vector.input) + if try ContentCorpusRecorder.output(for: vector.input) != output { + nondeterministic.append(vector.id) + } + lines.append(try ContentCorpusStore.line(vector, output: output)) + } + } + #expect(nondeterministic.isEmpty, "vectors that do not convert deterministically: \(nondeterministic)") + try ContentCorpusStore.write(lines) + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentInvariantTests.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentInvariantTests.swift new file mode 100644 index 000000000..e7aece41b --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentInvariantTests.swift @@ -0,0 +1,181 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +@testable import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit +import Testing + + +/// Invariant checks over one conversion, shared by the corpus pass so no vector converts twice. +enum ContentCorpusInvariants { + /// Every output a conversion emitted that its source type's catalog outputs do not name, and a primary output + /// that is not the catalog's first: identity enters only through the catalog's (role, discriminator) pairs. + static func uncatalogedOutputs(of outcome: ContentCorpusRecorder.Outcome) throws -> [String] { + guard case .converted(let set) = outcome else { + return [] + } + let context = try GoldenFixtures.context(sequence: ContentCorpusRecorder.sequence) + return try set.all.flatMap { conversion -> [String] in + let record = try context.identityScope.sourceRecord( + adapterID: "healthkit", + sourceType: conversion.source.type.rawValue, + repositoryScope: context.event.repositoryScope, + nativeRecordID: conversion.source.uuid.uuidString.lowercased() + ) + let cataloged = try HealthKitCatalog.outputs(for: conversion.source.type).map { output in + try record.output(role: output.role, discriminator: output.discriminator) + } + let emitted = [conversion.identifiers.primaryOutput] + conversion.identifiers.childOutputs + var problems = emitted.filter { !cataloged.contains($0) }.map { "\($0.identifier.value) is not a cataloged output" } + if cataloged.first != conversion.identifiers.primaryOutput { + problems.append("the primary output is not the catalog's first") + } + return problems + } + } +} + + +/// The content layer's permanent invariants (oracle O6) as today's public surface states them: rule-table totality, +/// unit compatibility, the reverse map as the inverse of the forward bindings, and corpus coverage of every row. +/// (Every emitted output being cataloged runs over the whole corpus in `ContentCorpusTests`; determinism is the +/// corpus reproducing across processes; Mobile milliseconds rounding from 1970 is `HealthKitEffectiveTimeTests`.) +@Suite +struct ContentInvariantTests { + /// Supported rows the adapter does not convert yet: food, the audiogram, and five characteristics. + private static let notYetConvertible: Set = [ + "HKCorrelationTypeIdentifierFood", "HKDataTypeIdentifierAudiogram", "HKCharacteristicTypeIdentifierBiologicalSex", + "HKCharacteristicTypeIdentifierBloodType", "HKCharacteristicTypeIdentifierDateOfBirth", + "HKCharacteristicTypeIdentifierFitzpatrickSkinType", "HKCharacteristicTypeIdentifierWheelchairUse" + ] + + /// Platform-exclusive rows the adapter carries as recording documents: the heartbeat series, the workout route, + /// CDA documents and the nine clinical record types. + private static let platformDocuments: Set = Set(ContentCorpusGrid.rows(prefix: "HKClinicalTypeIdentifier").map(\.sourceTypeIdentifier)) + .union([HKDataTypeIdentifierHeartbeatSeries, HKWorkoutRouteTypeIdentifier, "HKDocumentTypeIdentifierCDA"]) + + /// Rows that name no sample type, so no conversion can feed them. + private static let notSampleTypes: Set = Set(ContentCorpusGrid.rows(prefix: "HKCharacteristicTypeIdentifier").map(\.sourceTypeIdentifier)) + .union(["HKDataTypeUserAnnotatedMedicationConcept"]) + + /// Quantity rows that convert in a published unit binding: each one's unit measures its type. + private static var boundQuantityRows: [(row: HealthKitContractRow, unit: HKUnit)] { + ContentCorpusGrid.rows(prefix: "HKQuantityTypeIdentifier").compactMap { row in + guard row.implementationStatus == .supported, + let type = HealthKitSourceType(rawValue: row.sourceTypeIdentifier), + !HealthKitCatalog.outputs(for: type).isEmpty, + let code = ContentCorpusGrid.contract(row)?.quantity?.code, + let unit = HealthKitCatalog.unit(forUCUMCode: code) else { + return nil + } + return (row, unit) + } + } + + @Test("Every supported row mints outputs except the declared not-yet set; only platform-exclusive documents mint any otherwise") + func ruleTableIsTotal() throws { + var unconverted: Set = [] + var documents: Set = [] + for row in HealthKitContract.rows { + let type = try #require(HealthKitSourceType(rawValue: row.sourceTypeIdentifier)) + let outputs = HealthKitCatalog.outputs(for: type) + switch row.implementationStatus { + case .supported where outputs.isEmpty: + unconverted.insert(row.sourceTypeIdentifier) + case .platformExclusive where !outputs.isEmpty: + documents.insert(row.sourceTypeIdentifier) + #expect(outputs.map(\.resourceType) == [.documentReference], "\(row.sourceTypeIdentifier) mints \(outputs)") + case .intentionallyUnsupported: + #expect(outputs.isEmpty, "\(row.sourceTypeIdentifier) is intentionally unsupported but mints outputs") + default: + break + } + } + #expect(unconverted == Self.notYetConvertible) + #expect(documents == Self.platformDocuments) + } + + @Test("Every bound quantity unit measures its source type, and both lookups of every binding agree") + func quantityUnitsAreCompatible() throws { + let bound = Self.boundQuantityRows + for (row, unit) in bound { + let type = try #require(HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier(rawValue: row.sourceTypeIdentifier))) + #expect(type.is(compatibleWith: unit), "\(row.sourceTypeIdentifier) cannot be read in \(unit.unitString)") + } + // The 108 unit-read quantity rows, less body-mass index, whose contract no generated catalog carries yet. + #expect(bound.count == 107, "\(bound.count) quantity rows convert through a unit binding") + for binding in HealthKitCatalog.unitBindings { + let byCode = try #require(HealthKitCatalog.unit(forUCUMCode: binding.ucumCode)) + let bySpelling = try #require(HealthKitCatalog.unit(forUnitSpelling: binding.displayUnit)) + #expect(HKQuantity(unit: binding.unit, doubleValue: 1).is(compatibleWith: byCode), "\(binding.ucumCode)") + #expect(HKQuantity(unit: binding.unit, doubleValue: 1).is(compatibleWith: bySpelling), "\(binding.displayUnit)") + } + } + + @Test("The reverse map lands each measurement on the one quantity type that converts into it, and refuses the rest") + func reverseMapInvertsTheForwardBindings() throws { + var forward: [String: [String]] = [:] + for (row, _) in Self.boundQuantityRows { + if let id = row.measurementIDs.first { + forward[id, default: []].append(row.sourceTypeIdentifier) + } + } + var mismatches: [String] = [] + for contract in MeasurementCatalog.all + HealthKitMeasurementCatalog.all { + // Today's map, read without building a sample: HealthKit raises on samples it refuses to create. + let projected = (try? HealthKitSampleProjection.quantityTypeIdentifier(for: contract.id))?.rawValue + let expected = forward[contract.id].flatMap { $0.count == 1 ? $0.first : nil } + if projected != expected { + mismatches.append("\(contract.id): \(projected ?? "refused") != \(expected ?? "refused")") + } + } + #expect(mismatches.isEmpty, "\(mismatches)") + #expect(forward.values.contains { $0.count > 1 }, "some measurement is bound to several types and must refuse") + } + + @Test("Every row that names a sample type has a corpus vector converting it") + func everySampleRowIsInTheCorpus() { + let converted = Set(ContentCorpusGrid.vectors.compactMap { vector -> String? in + guard case .convert(let source) = vector.input else { + return nil + } + return source.record.sourceTypeIdentifier + }) + let rows = Set(HealthKitContract.rows.map(\.sourceTypeIdentifier)).subtracting(Self.notSampleTypes) + #if os(watchOS) + let missing = rows.subtracting(converted).filter { !$0.hasPrefix("HKClinicalTypeIdentifier") && $0 != "HKDocumentTypeIdentifierCDA" } + #else + let missing = rows.subtracting(converted) + #endif + #expect(missing.isEmpty, "rows without a conversion vector: \(missing.sorted())") + } +} + + +extension ContentCorpusRecord { + /// The source type a record of this payload converts as. + var sourceTypeIdentifier: String { + switch self { + case .quantity(let type, _, _), .category(let type, _), .correlation(let type, _), .assessment(let type, _), + .clinicalRecord(let type, _, _), .bare(let type, _): + type + case .workout: HKWorkoutTypeIdentifier + case .stateOfMind: HKSampleType.stateOfMindType().identifier + case .electrocardiogram: HKObjectType.electrocardiogramType().identifier + case .heartbeatSeries: HKDataTypeIdentifierHeartbeatSeries + case .workoutRoute: HKWorkoutRouteTypeIdentifier + case .cdaDocument: "HKDocumentTypeIdentifierCDA" + } + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift index e347f574d..d2f2433e2 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift @@ -106,7 +106,7 @@ struct GoldenOutline: Codable, Equatable { /// Names the first path where two token trees differ. -private enum TokenDiff { +enum TokenDiff { /// The first path where two token trees differ, or nil when they are equal. static func firstDifference(expected: LosslessJSONValue, actual: LosslessJSONValue, at path: String = "$") -> String? { switch (expected, actual) { diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitEffectiveTimeTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitEffectiveTimeTests.swift index ab45562a3..6322f2368 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitEffectiveTimeTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitEffectiveTimeTests.swift @@ -36,13 +36,13 @@ struct HealthKitEffectiveTimeTests { /// checked one at a time, each in its own pool, so a large sweep does not grow the heap concurrent suites measure. private static let sweepCount = ProcessInfo.processInfo.environment["GROVE_EFFECTIVE_TIME_SWEEP"].flatMap { Int($0) } ?? 3_000 - /// Named zones with odd, LMT, non-hour and DST offsets, plus both ±18 h extremes. + /// Named zones with odd, LMT, non-hour and DST offsets, plus both ±18 h extremes and a 37-second offset. private static let namedZones: [TimeZone] = [ "America/Los_Angeles", "Asia/Kolkata", "Asia/Kathmandu", "America/St_Johns", "Europe/Amsterdam", "Africa/Monrovia", "Australia/Lord_Howe", "Pacific/Chatham", "Pacific/Kiritimati" ].compactMap { TimeZone(identifier: $0) } + [64_800, -64_800, 37].compactMap { TimeZone(secondsFromGMT: $0) } - /// Twelve sweep zones: none (UTC) and every named or fixed zone above. + /// Thirteen sweep zones: none (UTC) and every named or fixed zone above. private static let zones: [TimeZone?] = [nil] + namedZones /// Ties, fractions, a repeated DST hour, the year 0 and 9999 boundaries, the 1582 reform, Foundation's diff --git a/Tests/GroveHealthKitFHIRTests/Resources/ContentCorpus/content-corpus.jsonl b/Tests/GroveHealthKitFHIRTests/Resources/ContentCorpus/content-corpus.jsonl new file mode 100644 index 000000000..523664f0d --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/Resources/ContentCorpus/content-corpus.jsonl @@ -0,0 +1,3003 @@ +{"id":"quantity/HKQuantityTypeIdentifierActiveEnergyBurned/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierActiveEnergyBurned","unit":"kcal","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"active-energy-burned","display":"Active energy burned","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierActiveEnergyBurned"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kx32A42PEll0Zb4uVHlNdwi1x04NuXnjyg_gdWSxfhQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:by7cX6De0XCHR0rVxwlhYhH2IsUPbTipqvFbRptDfnI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-active-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierActiveEnergyBurned/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierActiveEnergyBurned","unit":"kcal","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"active-energy-burned","display":"Active energy burned","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierActiveEnergyBurned"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kx32A42PEll0Zb4uVHlNdwi1x04NuXnjyg_gdWSxfhQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:by7cX6De0XCHR0rVxwlhYhH2IsUPbTipqvFbRptDfnI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-active-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierActiveEnergyBurned/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierActiveEnergyBurned","unit":"kcal","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"active-energy-burned","display":"Active energy burned","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierActiveEnergyBurned"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kx32A42PEll0Zb4uVHlNdwi1x04NuXnjyg_gdWSxfhQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:by7cX6De0XCHR0rVxwlhYhH2IsUPbTipqvFbRptDfnI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-active-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierActiveEnergyBurned/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierActiveEnergyBurned","unit":"kcal","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"active-energy-burned","display":"Active energy burned","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierActiveEnergyBurned"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kx32A42PEll0Zb4uVHlNdwi1x04NuXnjyg_gdWSxfhQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:by7cX6De0XCHR0rVxwlhYhH2IsUPbTipqvFbRptDfnI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-active-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierActiveEnergyBurned/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierActiveEnergyBurned","unit":"kcal","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"active-energy-burned","display":"Active energy burned","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierActiveEnergyBurned"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kx32A42PEll0Zb4uVHlNdwi1x04NuXnjyg_gdWSxfhQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:by7cX6De0XCHR0rVxwlhYhH2IsUPbTipqvFbRptDfnI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-active-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierActiveEnergyBurned/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierActiveEnergyBurned","unit":"kcal","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"active-energy-burned","display":"Active energy burned","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierActiveEnergyBurned"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kx32A42PEll0Zb4uVHlNdwi1x04NuXnjyg_gdWSxfhQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:by7cX6De0XCHR0rVxwlhYhH2IsUPbTipqvFbRptDfnI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-active-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierActiveEnergyBurned/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierActiveEnergyBurned","unit":"kcal","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.activeEnergyBurned, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierActiveEnergyBurned/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierActiveEnergyBurned","unit":"kcal","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.activeEnergyBurned, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierActiveEnergyBurned/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierActiveEnergyBurned","unit":"kcal","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.activeEnergyBurned, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAppleExerciseTime/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleExerciseTime","unit":"min","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"apple-exercise-time","display":"Apple exercise time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleExerciseTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:x0d9ev71_OKiPZg1428SHnoRSMYHpRq4F1rPDV5ZhYY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0Bwxf9MUhL7_L59w8a6RDVfo2b5F1NL8-yEto4TLzNU"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-exercise-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleExerciseTime/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleExerciseTime","unit":"min","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"apple-exercise-time","display":"Apple exercise time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleExerciseTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:x0d9ev71_OKiPZg1428SHnoRSMYHpRq4F1rPDV5ZhYY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0Bwxf9MUhL7_L59w8a6RDVfo2b5F1NL8-yEto4TLzNU"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-exercise-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleExerciseTime/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleExerciseTime","unit":"min","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"apple-exercise-time","display":"Apple exercise time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleExerciseTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:x0d9ev71_OKiPZg1428SHnoRSMYHpRq4F1rPDV5ZhYY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0Bwxf9MUhL7_L59w8a6RDVfo2b5F1NL8-yEto4TLzNU"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-exercise-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleExerciseTime/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleExerciseTime","unit":"min","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"apple-exercise-time","display":"Apple exercise time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleExerciseTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:x0d9ev71_OKiPZg1428SHnoRSMYHpRq4F1rPDV5ZhYY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0Bwxf9MUhL7_L59w8a6RDVfo2b5F1NL8-yEto4TLzNU"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-exercise-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleExerciseTime/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleExerciseTime","unit":"min","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"apple-exercise-time","display":"Apple exercise time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleExerciseTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:x0d9ev71_OKiPZg1428SHnoRSMYHpRq4F1rPDV5ZhYY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0Bwxf9MUhL7_L59w8a6RDVfo2b5F1NL8-yEto4TLzNU"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-exercise-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleExerciseTime/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleExerciseTime","unit":"min","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"apple-exercise-time","display":"Apple exercise time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleExerciseTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:x0d9ev71_OKiPZg1428SHnoRSMYHpRq4F1rPDV5ZhYY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0Bwxf9MUhL7_L59w8a6RDVfo2b5F1NL8-yEto4TLzNU"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-exercise-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleExerciseTime/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleExerciseTime","unit":"min","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleExerciseTime, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAppleExerciseTime/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleExerciseTime","unit":"min","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleExerciseTime, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAppleExerciseTime/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleExerciseTime","unit":"min","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleExerciseTime, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAppleMoveTime/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleMoveTime","unit":"min","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"apple-move-time","display":"Apple move time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleMoveTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AaB_AnYx7y0ud3cszFbB-5QyEbcYwECEmzJbW-_Djz0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4w9PBWp-qmgB7fME366hfY-LddIWG0p731lefRPuY1A"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-move-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleMoveTime/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleMoveTime","unit":"min","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"apple-move-time","display":"Apple move time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleMoveTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AaB_AnYx7y0ud3cszFbB-5QyEbcYwECEmzJbW-_Djz0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4w9PBWp-qmgB7fME366hfY-LddIWG0p731lefRPuY1A"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-move-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleMoveTime/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleMoveTime","unit":"min","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"apple-move-time","display":"Apple move time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleMoveTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AaB_AnYx7y0ud3cszFbB-5QyEbcYwECEmzJbW-_Djz0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4w9PBWp-qmgB7fME366hfY-LddIWG0p731lefRPuY1A"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-move-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleMoveTime/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleMoveTime","unit":"min","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"apple-move-time","display":"Apple move time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleMoveTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AaB_AnYx7y0ud3cszFbB-5QyEbcYwECEmzJbW-_Djz0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4w9PBWp-qmgB7fME366hfY-LddIWG0p731lefRPuY1A"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-move-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleMoveTime/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleMoveTime","unit":"min","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"apple-move-time","display":"Apple move time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleMoveTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AaB_AnYx7y0ud3cszFbB-5QyEbcYwECEmzJbW-_Djz0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4w9PBWp-qmgB7fME366hfY-LddIWG0p731lefRPuY1A"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-move-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleMoveTime/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleMoveTime","unit":"min","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"apple-move-time","display":"Apple move time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleMoveTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AaB_AnYx7y0ud3cszFbB-5QyEbcYwECEmzJbW-_Djz0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4w9PBWp-qmgB7fME366hfY-LddIWG0p731lefRPuY1A"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-move-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleMoveTime/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleMoveTime","unit":"min","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleMoveTime, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAppleMoveTime/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleMoveTime","unit":"min","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleMoveTime, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAppleMoveTime/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleMoveTime","unit":"min","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleMoveTime, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances","unit":"count","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"sleeping-breathing-disturbances","display":"Sleeping breathing disturbances","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:lF7njBwyRF48BVBPqfObHAClDievvm5Vy1QWXGcbg2s"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PTq104naXZTMLdb2IFhVtdFWnypYy1KwqJjG8jnvIwA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-sleeping-breathing-disturbances"]},"method":{"coding":[{"code":"session-rate","display":"Session rate","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/h","system":"http://unitsofmeasure.org","unit":"events/hour","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances","unit":"count","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"sleeping-breathing-disturbances","display":"Sleeping breathing disturbances","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:lF7njBwyRF48BVBPqfObHAClDievvm5Vy1QWXGcbg2s"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PTq104naXZTMLdb2IFhVtdFWnypYy1KwqJjG8jnvIwA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-sleeping-breathing-disturbances"]},"method":{"coding":[{"code":"session-rate","display":"Session rate","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/h","system":"http://unitsofmeasure.org","unit":"events/hour","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances","unit":"count","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"sleeping-breathing-disturbances","display":"Sleeping breathing disturbances","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:lF7njBwyRF48BVBPqfObHAClDievvm5Vy1QWXGcbg2s"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PTq104naXZTMLdb2IFhVtdFWnypYy1KwqJjG8jnvIwA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-sleeping-breathing-disturbances"]},"method":{"coding":[{"code":"session-rate","display":"Session rate","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/h","system":"http://unitsofmeasure.org","unit":"events/hour","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances","unit":"count","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"sleeping-breathing-disturbances","display":"Sleeping breathing disturbances","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:lF7njBwyRF48BVBPqfObHAClDievvm5Vy1QWXGcbg2s"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PTq104naXZTMLdb2IFhVtdFWnypYy1KwqJjG8jnvIwA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-sleeping-breathing-disturbances"]},"method":{"coding":[{"code":"session-rate","display":"Session rate","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/h","system":"http://unitsofmeasure.org","unit":"events/hour","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances","unit":"count","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"sleeping-breathing-disturbances","display":"Sleeping breathing disturbances","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:lF7njBwyRF48BVBPqfObHAClDievvm5Vy1QWXGcbg2s"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PTq104naXZTMLdb2IFhVtdFWnypYy1KwqJjG8jnvIwA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-sleeping-breathing-disturbances"]},"method":{"coding":[{"code":"session-rate","display":"Session rate","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/h","system":"http://unitsofmeasure.org","unit":"events/hour","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances","unit":"count","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"sleeping-breathing-disturbances","display":"Sleeping breathing disturbances","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:lF7njBwyRF48BVBPqfObHAClDievvm5Vy1QWXGcbg2s"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PTq104naXZTMLdb2IFhVtdFWnypYy1KwqJjG8jnvIwA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-sleeping-breathing-disturbances"]},"method":{"coding":[{"code":"session-rate","display":"Session rate","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/h","system":"http://unitsofmeasure.org","unit":"events/hour","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances","unit":"count","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleSleepingBreathingDisturbances, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances","unit":"count","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleSleepingBreathingDisturbances, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances","unit":"count","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleSleepingBreathingDisturbances, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAppleSleepingWristTemperature/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleSleepingWristTemperature","unit":"degC","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"61008-9","display":"Body surface temperature","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleSleepingWristTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:EBq6yQ16BSIkwRbom8axTzDkuieKUzkad__D3d6pm18"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3oToEJ4tdOm0wuEA6632dkhNKCxSVhggXHU6fy1EwSc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-skin-temperature","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleSleepingWristTemperature/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleSleepingWristTemperature","unit":"degC","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"61008-9","display":"Body surface temperature","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleSleepingWristTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:EBq6yQ16BSIkwRbom8axTzDkuieKUzkad__D3d6pm18"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3oToEJ4tdOm0wuEA6632dkhNKCxSVhggXHU6fy1EwSc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-skin-temperature","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleSleepingWristTemperature/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleSleepingWristTemperature","unit":"degC","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"61008-9","display":"Body surface temperature","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleSleepingWristTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:EBq6yQ16BSIkwRbom8axTzDkuieKUzkad__D3d6pm18"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3oToEJ4tdOm0wuEA6632dkhNKCxSVhggXHU6fy1EwSc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-skin-temperature","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleSleepingWristTemperature/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleSleepingWristTemperature","unit":"degC","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"61008-9","display":"Body surface temperature","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleSleepingWristTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:EBq6yQ16BSIkwRbom8axTzDkuieKUzkad__D3d6pm18"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3oToEJ4tdOm0wuEA6632dkhNKCxSVhggXHU6fy1EwSc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-skin-temperature","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleSleepingWristTemperature/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleSleepingWristTemperature","unit":"degC","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"61008-9","display":"Body surface temperature","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleSleepingWristTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:EBq6yQ16BSIkwRbom8axTzDkuieKUzkad__D3d6pm18"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3oToEJ4tdOm0wuEA6632dkhNKCxSVhggXHU6fy1EwSc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-skin-temperature","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleSleepingWristTemperature/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleSleepingWristTemperature","unit":"degC","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"61008-9","display":"Body surface temperature","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleSleepingWristTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:EBq6yQ16BSIkwRbom8axTzDkuieKUzkad__D3d6pm18"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3oToEJ4tdOm0wuEA6632dkhNKCxSVhggXHU6fy1EwSc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-skin-temperature","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleSleepingWristTemperature/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleSleepingWristTemperature","unit":"degC","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleSleepingWristTemperature, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAppleSleepingWristTemperature/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleSleepingWristTemperature","unit":"degC","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleSleepingWristTemperature, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAppleSleepingWristTemperature/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleSleepingWristTemperature","unit":"degC","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleSleepingWristTemperature, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAppleStandTime/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleStandTime","unit":"min","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"apple-stand-time","display":"Apple stand time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleStandTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Hw2qC_hew8UkTfpI8ROTjPzbk1ekCxXT06o_UGmIxkQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:daOjL79ce3xQTDRVgROPuo8dN8W_eSLZJ4nHGejd0ew"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-stand-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleStandTime/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleStandTime","unit":"min","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"apple-stand-time","display":"Apple stand time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleStandTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Hw2qC_hew8UkTfpI8ROTjPzbk1ekCxXT06o_UGmIxkQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:daOjL79ce3xQTDRVgROPuo8dN8W_eSLZJ4nHGejd0ew"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-stand-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleStandTime/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleStandTime","unit":"min","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"apple-stand-time","display":"Apple stand time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleStandTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Hw2qC_hew8UkTfpI8ROTjPzbk1ekCxXT06o_UGmIxkQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:daOjL79ce3xQTDRVgROPuo8dN8W_eSLZJ4nHGejd0ew"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-stand-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleStandTime/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleStandTime","unit":"min","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"apple-stand-time","display":"Apple stand time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleStandTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Hw2qC_hew8UkTfpI8ROTjPzbk1ekCxXT06o_UGmIxkQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:daOjL79ce3xQTDRVgROPuo8dN8W_eSLZJ4nHGejd0ew"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-stand-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleStandTime/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleStandTime","unit":"min","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"apple-stand-time","display":"Apple stand time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleStandTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Hw2qC_hew8UkTfpI8ROTjPzbk1ekCxXT06o_UGmIxkQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:daOjL79ce3xQTDRVgROPuo8dN8W_eSLZJ4nHGejd0ew"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-stand-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleStandTime/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleStandTime","unit":"min","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"apple-stand-time","display":"Apple stand time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleStandTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Hw2qC_hew8UkTfpI8ROTjPzbk1ekCxXT06o_UGmIxkQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:daOjL79ce3xQTDRVgROPuo8dN8W_eSLZJ4nHGejd0ew"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-stand-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleStandTime/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleStandTime","unit":"min","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleStandTime, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAppleStandTime/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleStandTime","unit":"min","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleStandTime, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAppleStandTime/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleStandTime","unit":"min","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleStandTime, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAppleWalkingSteadiness/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleWalkingSteadiness","unit":"%","value":0.25}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"walking-steadiness","display":"Walking steadiness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleWalkingSteadiness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:J7cX09Uxoqe6yR5aiTLmLgSf9o5DMaNq4ybOdSZB0rg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PNWdwvoy4bBXmF_lCQrDnEV6yW3CidJRTg5v4L_tPJQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-steadiness"]},"method":{"coding":[{"code":"rolling-mean","display":"Rolling mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":25}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleWalkingSteadiness/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleWalkingSteadiness","unit":"%","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"walking-steadiness","display":"Walking steadiness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleWalkingSteadiness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:J7cX09Uxoqe6yR5aiTLmLgSf9o5DMaNq4ybOdSZB0rg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PNWdwvoy4bBXmF_lCQrDnEV6yW3CidJRTg5v4L_tPJQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-steadiness"]},"method":{"coding":[{"code":"rolling-mean","display":"Rolling mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleWalkingSteadiness/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleWalkingSteadiness","unit":"%","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleWalkingSteadiness, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAppleWalkingSteadiness/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleWalkingSteadiness","unit":"%","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleWalkingSteadiness, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAppleWalkingSteadiness/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleWalkingSteadiness","unit":"%","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"walking-steadiness","display":"Walking steadiness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleWalkingSteadiness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:J7cX09Uxoqe6yR5aiTLmLgSf9o5DMaNq4ybOdSZB0rg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PNWdwvoy4bBXmF_lCQrDnEV6yW3CidJRTg5v4L_tPJQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-steadiness"]},"method":{"coding":[{"code":"rolling-mean","display":"Rolling mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":0.000009999999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleWalkingSteadiness/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleWalkingSteadiness","unit":"%","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleWalkingSteadiness, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAppleWalkingSteadiness/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleWalkingSteadiness","unit":"%","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleWalkingSteadiness, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAppleWalkingSteadiness/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleWalkingSteadiness","unit":"%","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleWalkingSteadiness, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAppleWalkingSteadiness/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleWalkingSteadiness","unit":"%","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleWalkingSteadiness, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAppleWalkingSteadiness/fraction-0.07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleWalkingSteadiness","unit":"%","value":0.07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"walking-steadiness","display":"Walking steadiness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleWalkingSteadiness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:J7cX09Uxoqe6yR5aiTLmLgSf9o5DMaNq4ybOdSZB0rg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PNWdwvoy4bBXmF_lCQrDnEV6yW3CidJRTg5v4L_tPJQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-steadiness"]},"method":{"coding":[{"code":"rolling-mean","display":"Rolling mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":7.000000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleWalkingSteadiness/fraction-0.14","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleWalkingSteadiness","unit":"%","value":0.14}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"walking-steadiness","display":"Walking steadiness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleWalkingSteadiness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:J7cX09Uxoqe6yR5aiTLmLgSf9o5DMaNq4ybOdSZB0rg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PNWdwvoy4bBXmF_lCQrDnEV6yW3CidJRTg5v4L_tPJQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-steadiness"]},"method":{"coding":[{"code":"rolling-mean","display":"Rolling mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":14.000000000000002}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleWalkingSteadiness/fraction-0.28","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleWalkingSteadiness","unit":"%","value":0.28}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"walking-steadiness","display":"Walking steadiness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleWalkingSteadiness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:J7cX09Uxoqe6yR5aiTLmLgSf9o5DMaNq4ybOdSZB0rg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PNWdwvoy4bBXmF_lCQrDnEV6yW3CidJRTg5v4L_tPJQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-steadiness"]},"method":{"coding":[{"code":"rolling-mean","display":"Rolling mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.000000000000004}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleWalkingSteadiness/fraction-0.282","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleWalkingSteadiness","unit":"%","value":0.282}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"walking-steadiness","display":"Walking steadiness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleWalkingSteadiness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:J7cX09Uxoqe6yR5aiTLmLgSf9o5DMaNq4ybOdSZB0rg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PNWdwvoy4bBXmF_lCQrDnEV6yW3CidJRTg5v4L_tPJQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-steadiness"]},"method":{"coding":[{"code":"rolling-mean","display":"Rolling mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.199999999999996}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleWalkingSteadiness/fraction-0.29","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleWalkingSteadiness","unit":"%","value":0.29}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"walking-steadiness","display":"Walking steadiness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleWalkingSteadiness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:J7cX09Uxoqe6yR5aiTLmLgSf9o5DMaNq4ybOdSZB0rg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PNWdwvoy4bBXmF_lCQrDnEV6yW3CidJRTg5v4L_tPJQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-steadiness"]},"method":{"coding":[{"code":"rolling-mean","display":"Rolling mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.999999999999996}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleWalkingSteadiness/fraction-0.55","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleWalkingSteadiness","unit":"%","value":0.55}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"walking-steadiness","display":"Walking steadiness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleWalkingSteadiness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:J7cX09Uxoqe6yR5aiTLmLgSf9o5DMaNq4ybOdSZB0rg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PNWdwvoy4bBXmF_lCQrDnEV6yW3CidJRTg5v4L_tPJQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-steadiness"]},"method":{"coding":[{"code":"rolling-mean","display":"Rolling mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":55.00000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleWalkingSteadiness/fraction-0.56","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleWalkingSteadiness","unit":"%","value":0.56}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"walking-steadiness","display":"Walking steadiness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleWalkingSteadiness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:J7cX09Uxoqe6yR5aiTLmLgSf9o5DMaNq4ybOdSZB0rg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PNWdwvoy4bBXmF_lCQrDnEV6yW3CidJRTg5v4L_tPJQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-steadiness"]},"method":{"coding":[{"code":"rolling-mean","display":"Rolling mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":56.00000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleWalkingSteadiness/fraction-0.57","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleWalkingSteadiness","unit":"%","value":0.57}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"walking-steadiness","display":"Walking steadiness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleWalkingSteadiness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:J7cX09Uxoqe6yR5aiTLmLgSf9o5DMaNq4ybOdSZB0rg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PNWdwvoy4bBXmF_lCQrDnEV6yW3CidJRTg5v4L_tPJQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-steadiness"]},"method":{"coding":[{"code":"rolling-mean","display":"Rolling mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":56.99999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleWalkingSteadiness/fraction-0.58","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleWalkingSteadiness","unit":"%","value":0.58}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"walking-steadiness","display":"Walking steadiness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleWalkingSteadiness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:J7cX09Uxoqe6yR5aiTLmLgSf9o5DMaNq4ybOdSZB0rg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PNWdwvoy4bBXmF_lCQrDnEV6yW3CidJRTg5v4L_tPJQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-steadiness"]},"method":{"coding":[{"code":"rolling-mean","display":"Rolling mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":57.99999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleWalkingSteadiness/fraction-0.98","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleWalkingSteadiness","unit":"%","value":0.98}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"walking-steadiness","display":"Walking steadiness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleWalkingSteadiness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:J7cX09Uxoqe6yR5aiTLmLgSf9o5DMaNq4ybOdSZB0rg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PNWdwvoy4bBXmF_lCQrDnEV6yW3CidJRTg5v4L_tPJQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-steadiness"]},"method":{"coding":[{"code":"rolling-mean","display":"Rolling mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":98}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleWalkingSteadiness/fraction-0.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleWalkingSteadiness","unit":"%","value":0.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"walking-steadiness","display":"Walking steadiness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleWalkingSteadiness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:J7cX09Uxoqe6yR5aiTLmLgSf9o5DMaNq4ybOdSZB0rg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PNWdwvoy4bBXmF_lCQrDnEV6yW3CidJRTg5v4L_tPJQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-steadiness"]},"method":{"coding":[{"code":"rolling-mean","display":"Rolling mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":50}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAppleWalkingSteadiness/fraction-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAppleWalkingSteadiness","unit":"%","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"walking-steadiness","display":"Walking steadiness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAppleWalkingSteadiness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:J7cX09Uxoqe6yR5aiTLmLgSf9o5DMaNq4ybOdSZB0rg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PNWdwvoy4bBXmF_lCQrDnEV6yW3CidJRTg5v4L_tPJQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-steadiness"]},"method":{"coding":[{"code":"rolling-mean","display":"Rolling mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":100}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAtrialFibrillationBurden/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAtrialFibrillationBurden","unit":"%","value":0.25}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"atrial-fibrillation-burden","display":"Atrial fibrillation burden","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAtrialFibrillationBurden"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:QFqNHSl1pCaoySLlNU3JbTR9Dg-8TbgZCkNEyQWPMJ4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WFpyh4vwA1cbaQ4A8WEmRPD7dvo6ZnjXF857GwsiwZQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-atrial-fibrillation-burden"]},"method":{"coding":[{"code":"percentage-of-time","display":"Percentage of time","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":25}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAtrialFibrillationBurden/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAtrialFibrillationBurden","unit":"%","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"atrial-fibrillation-burden","display":"Atrial fibrillation burden","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAtrialFibrillationBurden"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:QFqNHSl1pCaoySLlNU3JbTR9Dg-8TbgZCkNEyQWPMJ4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WFpyh4vwA1cbaQ4A8WEmRPD7dvo6ZnjXF857GwsiwZQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-atrial-fibrillation-burden"]},"method":{"coding":[{"code":"percentage-of-time","display":"Percentage of time","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAtrialFibrillationBurden/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAtrialFibrillationBurden","unit":"%","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.atrialFibrillationBurden, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAtrialFibrillationBurden/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAtrialFibrillationBurden","unit":"%","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.atrialFibrillationBurden, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAtrialFibrillationBurden/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAtrialFibrillationBurden","unit":"%","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"atrial-fibrillation-burden","display":"Atrial fibrillation burden","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAtrialFibrillationBurden"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:QFqNHSl1pCaoySLlNU3JbTR9Dg-8TbgZCkNEyQWPMJ4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WFpyh4vwA1cbaQ4A8WEmRPD7dvo6ZnjXF857GwsiwZQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-atrial-fibrillation-burden"]},"method":{"coding":[{"code":"percentage-of-time","display":"Percentage of time","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":0.000009999999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAtrialFibrillationBurden/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAtrialFibrillationBurden","unit":"%","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.atrialFibrillationBurden, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAtrialFibrillationBurden/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAtrialFibrillationBurden","unit":"%","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.atrialFibrillationBurden, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAtrialFibrillationBurden/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAtrialFibrillationBurden","unit":"%","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.atrialFibrillationBurden, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAtrialFibrillationBurden/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAtrialFibrillationBurden","unit":"%","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.atrialFibrillationBurden, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierAtrialFibrillationBurden/fraction-0.07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAtrialFibrillationBurden","unit":"%","value":0.07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"atrial-fibrillation-burden","display":"Atrial fibrillation burden","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAtrialFibrillationBurden"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:QFqNHSl1pCaoySLlNU3JbTR9Dg-8TbgZCkNEyQWPMJ4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WFpyh4vwA1cbaQ4A8WEmRPD7dvo6ZnjXF857GwsiwZQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-atrial-fibrillation-burden"]},"method":{"coding":[{"code":"percentage-of-time","display":"Percentage of time","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":7.000000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAtrialFibrillationBurden/fraction-0.14","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAtrialFibrillationBurden","unit":"%","value":0.14}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"atrial-fibrillation-burden","display":"Atrial fibrillation burden","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAtrialFibrillationBurden"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:QFqNHSl1pCaoySLlNU3JbTR9Dg-8TbgZCkNEyQWPMJ4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WFpyh4vwA1cbaQ4A8WEmRPD7dvo6ZnjXF857GwsiwZQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-atrial-fibrillation-burden"]},"method":{"coding":[{"code":"percentage-of-time","display":"Percentage of time","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":14.000000000000002}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAtrialFibrillationBurden/fraction-0.28","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAtrialFibrillationBurden","unit":"%","value":0.28}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"atrial-fibrillation-burden","display":"Atrial fibrillation burden","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAtrialFibrillationBurden"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:QFqNHSl1pCaoySLlNU3JbTR9Dg-8TbgZCkNEyQWPMJ4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WFpyh4vwA1cbaQ4A8WEmRPD7dvo6ZnjXF857GwsiwZQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-atrial-fibrillation-burden"]},"method":{"coding":[{"code":"percentage-of-time","display":"Percentage of time","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.000000000000004}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAtrialFibrillationBurden/fraction-0.282","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAtrialFibrillationBurden","unit":"%","value":0.282}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"atrial-fibrillation-burden","display":"Atrial fibrillation burden","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAtrialFibrillationBurden"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:QFqNHSl1pCaoySLlNU3JbTR9Dg-8TbgZCkNEyQWPMJ4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WFpyh4vwA1cbaQ4A8WEmRPD7dvo6ZnjXF857GwsiwZQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-atrial-fibrillation-burden"]},"method":{"coding":[{"code":"percentage-of-time","display":"Percentage of time","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.199999999999996}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAtrialFibrillationBurden/fraction-0.29","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAtrialFibrillationBurden","unit":"%","value":0.29}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"atrial-fibrillation-burden","display":"Atrial fibrillation burden","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAtrialFibrillationBurden"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:QFqNHSl1pCaoySLlNU3JbTR9Dg-8TbgZCkNEyQWPMJ4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WFpyh4vwA1cbaQ4A8WEmRPD7dvo6ZnjXF857GwsiwZQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-atrial-fibrillation-burden"]},"method":{"coding":[{"code":"percentage-of-time","display":"Percentage of time","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.999999999999996}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAtrialFibrillationBurden/fraction-0.55","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAtrialFibrillationBurden","unit":"%","value":0.55}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"atrial-fibrillation-burden","display":"Atrial fibrillation burden","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAtrialFibrillationBurden"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:QFqNHSl1pCaoySLlNU3JbTR9Dg-8TbgZCkNEyQWPMJ4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WFpyh4vwA1cbaQ4A8WEmRPD7dvo6ZnjXF857GwsiwZQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-atrial-fibrillation-burden"]},"method":{"coding":[{"code":"percentage-of-time","display":"Percentage of time","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":55.00000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAtrialFibrillationBurden/fraction-0.56","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAtrialFibrillationBurden","unit":"%","value":0.56}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"atrial-fibrillation-burden","display":"Atrial fibrillation burden","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAtrialFibrillationBurden"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:QFqNHSl1pCaoySLlNU3JbTR9Dg-8TbgZCkNEyQWPMJ4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WFpyh4vwA1cbaQ4A8WEmRPD7dvo6ZnjXF857GwsiwZQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-atrial-fibrillation-burden"]},"method":{"coding":[{"code":"percentage-of-time","display":"Percentage of time","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":56.00000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAtrialFibrillationBurden/fraction-0.57","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAtrialFibrillationBurden","unit":"%","value":0.57}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"atrial-fibrillation-burden","display":"Atrial fibrillation burden","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAtrialFibrillationBurden"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:QFqNHSl1pCaoySLlNU3JbTR9Dg-8TbgZCkNEyQWPMJ4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WFpyh4vwA1cbaQ4A8WEmRPD7dvo6ZnjXF857GwsiwZQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-atrial-fibrillation-burden"]},"method":{"coding":[{"code":"percentage-of-time","display":"Percentage of time","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":56.99999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAtrialFibrillationBurden/fraction-0.58","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAtrialFibrillationBurden","unit":"%","value":0.58}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"atrial-fibrillation-burden","display":"Atrial fibrillation burden","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAtrialFibrillationBurden"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:QFqNHSl1pCaoySLlNU3JbTR9Dg-8TbgZCkNEyQWPMJ4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WFpyh4vwA1cbaQ4A8WEmRPD7dvo6ZnjXF857GwsiwZQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-atrial-fibrillation-burden"]},"method":{"coding":[{"code":"percentage-of-time","display":"Percentage of time","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":57.99999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAtrialFibrillationBurden/fraction-0.98","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAtrialFibrillationBurden","unit":"%","value":0.98}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"atrial-fibrillation-burden","display":"Atrial fibrillation burden","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAtrialFibrillationBurden"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:QFqNHSl1pCaoySLlNU3JbTR9Dg-8TbgZCkNEyQWPMJ4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WFpyh4vwA1cbaQ4A8WEmRPD7dvo6ZnjXF857GwsiwZQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-atrial-fibrillation-burden"]},"method":{"coding":[{"code":"percentage-of-time","display":"Percentage of time","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":98}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAtrialFibrillationBurden/fraction-0.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAtrialFibrillationBurden","unit":"%","value":0.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"atrial-fibrillation-burden","display":"Atrial fibrillation burden","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAtrialFibrillationBurden"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:QFqNHSl1pCaoySLlNU3JbTR9Dg-8TbgZCkNEyQWPMJ4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WFpyh4vwA1cbaQ4A8WEmRPD7dvo6ZnjXF857GwsiwZQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-atrial-fibrillation-burden"]},"method":{"coding":[{"code":"percentage-of-time","display":"Percentage of time","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":50}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierAtrialFibrillationBurden/fraction-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierAtrialFibrillationBurden","unit":"%","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"atrial-fibrillation-burden","display":"Atrial fibrillation burden","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierAtrialFibrillationBurden"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:QFqNHSl1pCaoySLlNU3JbTR9Dg-8TbgZCkNEyQWPMJ4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WFpyh4vwA1cbaQ4A8WEmRPD7dvo6ZnjXF857GwsiwZQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-atrial-fibrillation-burden"]},"method":{"coding":[{"code":"percentage-of-time","display":"Percentage of time","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":100}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBasalBodyTemperature/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBasalBodyTemperature","unit":"degC","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"basal-body-temperature","display":"Basal body temperature","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBasalBodyTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5LymzG84PFsxQTrHHdxi5FVkyqGJ7rXV24LAbrDISPA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:COK232J8yTuX4xZPiSZwvVK23RpizedCioxUAf8r-zM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-basal-body-temperature","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBasalBodyTemperature/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBasalBodyTemperature","unit":"degC","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"basal-body-temperature","display":"Basal body temperature","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBasalBodyTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5LymzG84PFsxQTrHHdxi5FVkyqGJ7rXV24LAbrDISPA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:COK232J8yTuX4xZPiSZwvVK23RpizedCioxUAf8r-zM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-basal-body-temperature","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBasalBodyTemperature/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBasalBodyTemperature","unit":"degC","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"basal-body-temperature","display":"Basal body temperature","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBasalBodyTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5LymzG84PFsxQTrHHdxi5FVkyqGJ7rXV24LAbrDISPA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:COK232J8yTuX4xZPiSZwvVK23RpizedCioxUAf8r-zM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-basal-body-temperature","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBasalBodyTemperature/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBasalBodyTemperature","unit":"degC","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"basal-body-temperature","display":"Basal body temperature","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBasalBodyTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5LymzG84PFsxQTrHHdxi5FVkyqGJ7rXV24LAbrDISPA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:COK232J8yTuX4xZPiSZwvVK23RpizedCioxUAf8r-zM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-basal-body-temperature","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBasalBodyTemperature/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBasalBodyTemperature","unit":"degC","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"basal-body-temperature","display":"Basal body temperature","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBasalBodyTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5LymzG84PFsxQTrHHdxi5FVkyqGJ7rXV24LAbrDISPA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:COK232J8yTuX4xZPiSZwvVK23RpizedCioxUAf8r-zM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-basal-body-temperature","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBasalBodyTemperature/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBasalBodyTemperature","unit":"degC","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"basal-body-temperature","display":"Basal body temperature","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBasalBodyTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5LymzG84PFsxQTrHHdxi5FVkyqGJ7rXV24LAbrDISPA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:COK232J8yTuX4xZPiSZwvVK23RpizedCioxUAf8r-zM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-basal-body-temperature","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBasalBodyTemperature/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBasalBodyTemperature","unit":"degC","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.basalBodyTemperature, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBasalBodyTemperature/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBasalBodyTemperature","unit":"degC","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.basalBodyTemperature, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBasalBodyTemperature/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBasalBodyTemperature","unit":"degC","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.basalBodyTemperature, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBasalEnergyBurned/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBasalEnergyBurned","unit":"kcal","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"basal-energy-burned","display":"Basal energy burned","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBasalEnergyBurned"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:nLDKJ2yTeVZ7FnLjrnsSmt8lAIcQrSWjN6EAYGqtqkI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3WJq1-cJKeCOCSnqD0lK8N70nChwgPuw5f-A3Xvxn2s"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-basal-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBasalEnergyBurned/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBasalEnergyBurned","unit":"kcal","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"basal-energy-burned","display":"Basal energy burned","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBasalEnergyBurned"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:nLDKJ2yTeVZ7FnLjrnsSmt8lAIcQrSWjN6EAYGqtqkI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3WJq1-cJKeCOCSnqD0lK8N70nChwgPuw5f-A3Xvxn2s"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-basal-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBasalEnergyBurned/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBasalEnergyBurned","unit":"kcal","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"basal-energy-burned","display":"Basal energy burned","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBasalEnergyBurned"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:nLDKJ2yTeVZ7FnLjrnsSmt8lAIcQrSWjN6EAYGqtqkI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3WJq1-cJKeCOCSnqD0lK8N70nChwgPuw5f-A3Xvxn2s"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-basal-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBasalEnergyBurned/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBasalEnergyBurned","unit":"kcal","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"basal-energy-burned","display":"Basal energy burned","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBasalEnergyBurned"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:nLDKJ2yTeVZ7FnLjrnsSmt8lAIcQrSWjN6EAYGqtqkI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3WJq1-cJKeCOCSnqD0lK8N70nChwgPuw5f-A3Xvxn2s"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-basal-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBasalEnergyBurned/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBasalEnergyBurned","unit":"kcal","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"basal-energy-burned","display":"Basal energy burned","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBasalEnergyBurned"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:nLDKJ2yTeVZ7FnLjrnsSmt8lAIcQrSWjN6EAYGqtqkI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3WJq1-cJKeCOCSnqD0lK8N70nChwgPuw5f-A3Xvxn2s"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-basal-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBasalEnergyBurned/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBasalEnergyBurned","unit":"kcal","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"basal-energy-burned","display":"Basal energy burned","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBasalEnergyBurned"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:nLDKJ2yTeVZ7FnLjrnsSmt8lAIcQrSWjN6EAYGqtqkI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3WJq1-cJKeCOCSnqD0lK8N70nChwgPuw5f-A3Xvxn2s"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-basal-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBasalEnergyBurned/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBasalEnergyBurned","unit":"kcal","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.basalEnergyBurned, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBasalEnergyBurned/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBasalEnergyBurned","unit":"kcal","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.basalEnergyBurned, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBasalEnergyBurned/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBasalEnergyBurned","unit":"kcal","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.basalEnergyBurned, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodAlcoholContent/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodAlcoholContent","unit":"%","value":0.25}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"blood-alcohol-content","display":"Blood alcohol content","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBloodAlcoholContent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:umtRiN4qMRIu_eER1YUc5fT2rhgD4I2tIUcD_d-Nbfw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5tp9BhWRjAxEGuFMm_UyZXEpxakSh46dcqNPE-N4wLI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-blood-alcohol-content"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":25}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBloodAlcoholContent/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodAlcoholContent","unit":"%","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"blood-alcohol-content","display":"Blood alcohol content","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBloodAlcoholContent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:umtRiN4qMRIu_eER1YUc5fT2rhgD4I2tIUcD_d-Nbfw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5tp9BhWRjAxEGuFMm_UyZXEpxakSh46dcqNPE-N4wLI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-blood-alcohol-content"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBloodAlcoholContent/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodAlcoholContent","unit":"%","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bloodAlcoholContent, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodAlcoholContent/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodAlcoholContent","unit":"%","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bloodAlcoholContent, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodAlcoholContent/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodAlcoholContent","unit":"%","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"blood-alcohol-content","display":"Blood alcohol content","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBloodAlcoholContent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:umtRiN4qMRIu_eER1YUc5fT2rhgD4I2tIUcD_d-Nbfw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5tp9BhWRjAxEGuFMm_UyZXEpxakSh46dcqNPE-N4wLI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-blood-alcohol-content"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":0.000009999999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBloodAlcoholContent/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodAlcoholContent","unit":"%","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bloodAlcoholContent, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodAlcoholContent/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodAlcoholContent","unit":"%","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bloodAlcoholContent, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodAlcoholContent/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodAlcoholContent","unit":"%","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bloodAlcoholContent, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodAlcoholContent/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodAlcoholContent","unit":"%","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bloodAlcoholContent, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodAlcoholContent/fraction-0.07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodAlcoholContent","unit":"%","value":0.07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"blood-alcohol-content","display":"Blood alcohol content","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBloodAlcoholContent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:umtRiN4qMRIu_eER1YUc5fT2rhgD4I2tIUcD_d-Nbfw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5tp9BhWRjAxEGuFMm_UyZXEpxakSh46dcqNPE-N4wLI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-blood-alcohol-content"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":7.000000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBloodAlcoholContent/fraction-0.14","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodAlcoholContent","unit":"%","value":0.14}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"blood-alcohol-content","display":"Blood alcohol content","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBloodAlcoholContent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:umtRiN4qMRIu_eER1YUc5fT2rhgD4I2tIUcD_d-Nbfw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5tp9BhWRjAxEGuFMm_UyZXEpxakSh46dcqNPE-N4wLI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-blood-alcohol-content"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":14.000000000000002}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBloodAlcoholContent/fraction-0.28","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodAlcoholContent","unit":"%","value":0.28}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"blood-alcohol-content","display":"Blood alcohol content","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBloodAlcoholContent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:umtRiN4qMRIu_eER1YUc5fT2rhgD4I2tIUcD_d-Nbfw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5tp9BhWRjAxEGuFMm_UyZXEpxakSh46dcqNPE-N4wLI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-blood-alcohol-content"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.000000000000004}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBloodAlcoholContent/fraction-0.282","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodAlcoholContent","unit":"%","value":0.282}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"blood-alcohol-content","display":"Blood alcohol content","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBloodAlcoholContent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:umtRiN4qMRIu_eER1YUc5fT2rhgD4I2tIUcD_d-Nbfw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5tp9BhWRjAxEGuFMm_UyZXEpxakSh46dcqNPE-N4wLI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-blood-alcohol-content"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.199999999999996}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBloodAlcoholContent/fraction-0.29","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodAlcoholContent","unit":"%","value":0.29}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"blood-alcohol-content","display":"Blood alcohol content","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBloodAlcoholContent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:umtRiN4qMRIu_eER1YUc5fT2rhgD4I2tIUcD_d-Nbfw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5tp9BhWRjAxEGuFMm_UyZXEpxakSh46dcqNPE-N4wLI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-blood-alcohol-content"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.999999999999996}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBloodAlcoholContent/fraction-0.55","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodAlcoholContent","unit":"%","value":0.55}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"blood-alcohol-content","display":"Blood alcohol content","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBloodAlcoholContent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:umtRiN4qMRIu_eER1YUc5fT2rhgD4I2tIUcD_d-Nbfw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5tp9BhWRjAxEGuFMm_UyZXEpxakSh46dcqNPE-N4wLI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-blood-alcohol-content"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":55.00000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBloodAlcoholContent/fraction-0.56","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodAlcoholContent","unit":"%","value":0.56}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"blood-alcohol-content","display":"Blood alcohol content","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBloodAlcoholContent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:umtRiN4qMRIu_eER1YUc5fT2rhgD4I2tIUcD_d-Nbfw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5tp9BhWRjAxEGuFMm_UyZXEpxakSh46dcqNPE-N4wLI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-blood-alcohol-content"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":56.00000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBloodAlcoholContent/fraction-0.57","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodAlcoholContent","unit":"%","value":0.57}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"blood-alcohol-content","display":"Blood alcohol content","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBloodAlcoholContent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:umtRiN4qMRIu_eER1YUc5fT2rhgD4I2tIUcD_d-Nbfw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5tp9BhWRjAxEGuFMm_UyZXEpxakSh46dcqNPE-N4wLI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-blood-alcohol-content"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":56.99999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBloodAlcoholContent/fraction-0.58","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodAlcoholContent","unit":"%","value":0.58}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"blood-alcohol-content","display":"Blood alcohol content","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBloodAlcoholContent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:umtRiN4qMRIu_eER1YUc5fT2rhgD4I2tIUcD_d-Nbfw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5tp9BhWRjAxEGuFMm_UyZXEpxakSh46dcqNPE-N4wLI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-blood-alcohol-content"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":57.99999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBloodAlcoholContent/fraction-0.98","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodAlcoholContent","unit":"%","value":0.98}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"blood-alcohol-content","display":"Blood alcohol content","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBloodAlcoholContent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:umtRiN4qMRIu_eER1YUc5fT2rhgD4I2tIUcD_d-Nbfw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5tp9BhWRjAxEGuFMm_UyZXEpxakSh46dcqNPE-N4wLI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-blood-alcohol-content"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":98}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBloodAlcoholContent/fraction-0.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodAlcoholContent","unit":"%","value":0.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"blood-alcohol-content","display":"Blood alcohol content","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBloodAlcoholContent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:umtRiN4qMRIu_eER1YUc5fT2rhgD4I2tIUcD_d-Nbfw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5tp9BhWRjAxEGuFMm_UyZXEpxakSh46dcqNPE-N4wLI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-blood-alcohol-content"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":50}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBloodAlcoholContent/fraction-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodAlcoholContent","unit":"%","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"blood-alcohol-content","display":"Blood alcohol content","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBloodAlcoholContent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:umtRiN4qMRIu_eER1YUc5fT2rhgD4I2tIUcD_d-Nbfw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5tp9BhWRjAxEGuFMm_UyZXEpxakSh46dcqNPE-N4wLI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-blood-alcohol-content"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":100}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBloodGlucose/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodGlucose","unit":"mg/dL","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"2339-0","display":"Glucose [Mass/volume] in Blood","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBloodGlucose"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qvDuL1Wbl6LMUlyu_22LFAwiOFuJP8TmKBUbJckmZNk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_yR4sXoau44VkcKMiVWaenSYlvQ0HGr5GT4No7NFvoY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-glucose-unspecified-specimen","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg/dL","system":"http://unitsofmeasure.org","unit":"mg/dL","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBloodGlucose/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodGlucose","unit":"mg/dL","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"2339-0","display":"Glucose [Mass/volume] in Blood","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBloodGlucose"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qvDuL1Wbl6LMUlyu_22LFAwiOFuJP8TmKBUbJckmZNk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_yR4sXoau44VkcKMiVWaenSYlvQ0HGr5GT4No7NFvoY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-glucose-unspecified-specimen","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg/dL","system":"http://unitsofmeasure.org","unit":"mg/dL","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBloodGlucose/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodGlucose","unit":"mg/dL","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"2339-0","display":"Glucose [Mass/volume] in Blood","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBloodGlucose"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qvDuL1Wbl6LMUlyu_22LFAwiOFuJP8TmKBUbJckmZNk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_yR4sXoau44VkcKMiVWaenSYlvQ0HGr5GT4No7NFvoY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-glucose-unspecified-specimen","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg/dL","system":"http://unitsofmeasure.org","unit":"mg/dL","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBloodGlucose/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodGlucose","unit":"mg/dL","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"2339-0","display":"Glucose [Mass/volume] in Blood","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBloodGlucose"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qvDuL1Wbl6LMUlyu_22LFAwiOFuJP8TmKBUbJckmZNk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_yR4sXoau44VkcKMiVWaenSYlvQ0HGr5GT4No7NFvoY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-glucose-unspecified-specimen","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg/dL","system":"http://unitsofmeasure.org","unit":"mg/dL","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBloodGlucose/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodGlucose","unit":"mg/dL","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"2339-0","display":"Glucose [Mass/volume] in Blood","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBloodGlucose"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qvDuL1Wbl6LMUlyu_22LFAwiOFuJP8TmKBUbJckmZNk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_yR4sXoau44VkcKMiVWaenSYlvQ0HGr5GT4No7NFvoY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-glucose-unspecified-specimen","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg/dL","system":"http://unitsofmeasure.org","unit":"mg/dL","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBloodGlucose/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodGlucose","unit":"mg/dL","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"2339-0","display":"Glucose [Mass/volume] in Blood","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBloodGlucose"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qvDuL1Wbl6LMUlyu_22LFAwiOFuJP8TmKBUbJckmZNk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_yR4sXoau44VkcKMiVWaenSYlvQ0HGr5GT4No7NFvoY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-glucose-unspecified-specimen","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg/dL","system":"http://unitsofmeasure.org","unit":"mg/dL","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBloodGlucose/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodGlucose","unit":"mg/dL","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bloodGlucose, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodGlucose/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodGlucose","unit":"mg/dL","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bloodGlucose, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodGlucose/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodGlucose","unit":"mg/dL","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bloodGlucose, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodPressureDiastolic/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.component-requires-correlation","error":"componentRequiresCorrelation(GroveHealthKitFHIR.HealthKitSourceType.bloodPressureDiastolic)","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodPressureDiastolic/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.component-requires-correlation","error":"componentRequiresCorrelation(GroveHealthKitFHIR.HealthKitSourceType.bloodPressureDiastolic)","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodPressureDiastolic/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.component-requires-correlation","error":"componentRequiresCorrelation(GroveHealthKitFHIR.HealthKitSourceType.bloodPressureDiastolic)","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodPressureDiastolic/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.component-requires-correlation","error":"componentRequiresCorrelation(GroveHealthKitFHIR.HealthKitSourceType.bloodPressureDiastolic)","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodPressureDiastolic/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.component-requires-correlation","error":"componentRequiresCorrelation(GroveHealthKitFHIR.HealthKitSourceType.bloodPressureDiastolic)","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodPressureDiastolic/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.component-requires-correlation","error":"componentRequiresCorrelation(GroveHealthKitFHIR.HealthKitSourceType.bloodPressureDiastolic)","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodPressureDiastolic/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.component-requires-correlation","error":"componentRequiresCorrelation(GroveHealthKitFHIR.HealthKitSourceType.bloodPressureDiastolic)","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodPressureDiastolic/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.component-requires-correlation","error":"componentRequiresCorrelation(GroveHealthKitFHIR.HealthKitSourceType.bloodPressureDiastolic)","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodPressureDiastolic/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.component-requires-correlation","error":"componentRequiresCorrelation(GroveHealthKitFHIR.HealthKitSourceType.bloodPressureDiastolic)","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodPressureSystolic/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.component-requires-correlation","error":"componentRequiresCorrelation(GroveHealthKitFHIR.HealthKitSourceType.bloodPressureSystolic)","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodPressureSystolic/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.component-requires-correlation","error":"componentRequiresCorrelation(GroveHealthKitFHIR.HealthKitSourceType.bloodPressureSystolic)","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodPressureSystolic/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.component-requires-correlation","error":"componentRequiresCorrelation(GroveHealthKitFHIR.HealthKitSourceType.bloodPressureSystolic)","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodPressureSystolic/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.component-requires-correlation","error":"componentRequiresCorrelation(GroveHealthKitFHIR.HealthKitSourceType.bloodPressureSystolic)","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodPressureSystolic/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.component-requires-correlation","error":"componentRequiresCorrelation(GroveHealthKitFHIR.HealthKitSourceType.bloodPressureSystolic)","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodPressureSystolic/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.component-requires-correlation","error":"componentRequiresCorrelation(GroveHealthKitFHIR.HealthKitSourceType.bloodPressureSystolic)","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodPressureSystolic/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.component-requires-correlation","error":"componentRequiresCorrelation(GroveHealthKitFHIR.HealthKitSourceType.bloodPressureSystolic)","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodPressureSystolic/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.component-requires-correlation","error":"componentRequiresCorrelation(GroveHealthKitFHIR.HealthKitSourceType.bloodPressureSystolic)","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierBloodPressureSystolic/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.component-requires-correlation","error":"componentRequiresCorrelation(GroveHealthKitFHIR.HealthKitSourceType.bloodPressureSystolic)","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierBodyFatPercentage/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyFatPercentage","unit":"%","value":0.25}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"41982-0","display":"Percentage of body fat Measured","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyFatPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NycJS1T8FMgGFz_eGe-GiLOLQaCaRCJj4fEinjWc2IA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2lrRRHLMevrgCqFOghTeOSpBPtGYPOgWWwvEnQw_ykI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-fat-percentage","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":25}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyFatPercentage/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyFatPercentage","unit":"%","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"41982-0","display":"Percentage of body fat Measured","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyFatPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NycJS1T8FMgGFz_eGe-GiLOLQaCaRCJj4fEinjWc2IA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2lrRRHLMevrgCqFOghTeOSpBPtGYPOgWWwvEnQw_ykI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-fat-percentage","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyFatPercentage/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyFatPercentage","unit":"%","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bodyFatPercentage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBodyFatPercentage/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyFatPercentage","unit":"%","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bodyFatPercentage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBodyFatPercentage/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyFatPercentage","unit":"%","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"41982-0","display":"Percentage of body fat Measured","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyFatPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NycJS1T8FMgGFz_eGe-GiLOLQaCaRCJj4fEinjWc2IA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2lrRRHLMevrgCqFOghTeOSpBPtGYPOgWWwvEnQw_ykI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-fat-percentage","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":0.000009999999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyFatPercentage/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyFatPercentage","unit":"%","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bodyFatPercentage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBodyFatPercentage/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyFatPercentage","unit":"%","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bodyFatPercentage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBodyFatPercentage/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyFatPercentage","unit":"%","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bodyFatPercentage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBodyFatPercentage/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyFatPercentage","unit":"%","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bodyFatPercentage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBodyFatPercentage/fraction-0.07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyFatPercentage","unit":"%","value":0.07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"41982-0","display":"Percentage of body fat Measured","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyFatPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NycJS1T8FMgGFz_eGe-GiLOLQaCaRCJj4fEinjWc2IA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2lrRRHLMevrgCqFOghTeOSpBPtGYPOgWWwvEnQw_ykI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-fat-percentage","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":7.000000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyFatPercentage/fraction-0.14","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyFatPercentage","unit":"%","value":0.14}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"41982-0","display":"Percentage of body fat Measured","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyFatPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NycJS1T8FMgGFz_eGe-GiLOLQaCaRCJj4fEinjWc2IA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2lrRRHLMevrgCqFOghTeOSpBPtGYPOgWWwvEnQw_ykI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-fat-percentage","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":14.000000000000002}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyFatPercentage/fraction-0.28","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyFatPercentage","unit":"%","value":0.28}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"41982-0","display":"Percentage of body fat Measured","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyFatPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NycJS1T8FMgGFz_eGe-GiLOLQaCaRCJj4fEinjWc2IA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2lrRRHLMevrgCqFOghTeOSpBPtGYPOgWWwvEnQw_ykI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-fat-percentage","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.000000000000004}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyFatPercentage/fraction-0.282","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyFatPercentage","unit":"%","value":0.282}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"41982-0","display":"Percentage of body fat Measured","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyFatPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NycJS1T8FMgGFz_eGe-GiLOLQaCaRCJj4fEinjWc2IA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2lrRRHLMevrgCqFOghTeOSpBPtGYPOgWWwvEnQw_ykI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-fat-percentage","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.199999999999996}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyFatPercentage/fraction-0.29","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyFatPercentage","unit":"%","value":0.29}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"41982-0","display":"Percentage of body fat Measured","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyFatPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NycJS1T8FMgGFz_eGe-GiLOLQaCaRCJj4fEinjWc2IA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2lrRRHLMevrgCqFOghTeOSpBPtGYPOgWWwvEnQw_ykI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-fat-percentage","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.999999999999996}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyFatPercentage/fraction-0.55","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyFatPercentage","unit":"%","value":0.55}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"41982-0","display":"Percentage of body fat Measured","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyFatPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NycJS1T8FMgGFz_eGe-GiLOLQaCaRCJj4fEinjWc2IA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2lrRRHLMevrgCqFOghTeOSpBPtGYPOgWWwvEnQw_ykI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-fat-percentage","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":55.00000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyFatPercentage/fraction-0.56","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyFatPercentage","unit":"%","value":0.56}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"41982-0","display":"Percentage of body fat Measured","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyFatPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NycJS1T8FMgGFz_eGe-GiLOLQaCaRCJj4fEinjWc2IA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2lrRRHLMevrgCqFOghTeOSpBPtGYPOgWWwvEnQw_ykI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-fat-percentage","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":56.00000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyFatPercentage/fraction-0.57","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyFatPercentage","unit":"%","value":0.57}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"41982-0","display":"Percentage of body fat Measured","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyFatPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NycJS1T8FMgGFz_eGe-GiLOLQaCaRCJj4fEinjWc2IA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2lrRRHLMevrgCqFOghTeOSpBPtGYPOgWWwvEnQw_ykI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-fat-percentage","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":56.99999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyFatPercentage/fraction-0.58","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyFatPercentage","unit":"%","value":0.58}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"41982-0","display":"Percentage of body fat Measured","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyFatPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NycJS1T8FMgGFz_eGe-GiLOLQaCaRCJj4fEinjWc2IA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2lrRRHLMevrgCqFOghTeOSpBPtGYPOgWWwvEnQw_ykI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-fat-percentage","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":57.99999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyFatPercentage/fraction-0.98","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyFatPercentage","unit":"%","value":0.98}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"41982-0","display":"Percentage of body fat Measured","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyFatPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NycJS1T8FMgGFz_eGe-GiLOLQaCaRCJj4fEinjWc2IA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2lrRRHLMevrgCqFOghTeOSpBPtGYPOgWWwvEnQw_ykI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-fat-percentage","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":98}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyFatPercentage/fraction-0.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyFatPercentage","unit":"%","value":0.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"41982-0","display":"Percentage of body fat Measured","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyFatPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NycJS1T8FMgGFz_eGe-GiLOLQaCaRCJj4fEinjWc2IA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2lrRRHLMevrgCqFOghTeOSpBPtGYPOgWWwvEnQw_ykI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-fat-percentage","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":50}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyFatPercentage/fraction-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyFatPercentage","unit":"%","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"41982-0","display":"Percentage of body fat Measured","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyFatPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NycJS1T8FMgGFz_eGe-GiLOLQaCaRCJj4fEinjWc2IA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2lrRRHLMevrgCqFOghTeOSpBPtGYPOgWWwvEnQw_ykI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-fat-percentage","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":100}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyMass/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyMass/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyMass/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyMass/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyMass/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyMass/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyMass/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bodyMass, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBodyMass/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bodyMass, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBodyMass/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bodyMass, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBodyMassIndex/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMassIndex","unit":"count","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"39156-5","display":"Body mass index (BMI) [Ratio]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMassIndex"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pRTh3HYkiDpZH83qB9wMAaKHXyiGI7iVhC8fic50yus"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:V_fDbUNnh1fvFKOiulWKg72jVDQCfgz_K6bIiMtzwBo"}],"meta":{"profile":["http://hl7.org/fhir/StructureDefinition/bmi","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg/m2","system":"http://unitsofmeasure.org","unit":"kg/m2","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyMassIndex/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMassIndex","unit":"count","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"39156-5","display":"Body mass index (BMI) [Ratio]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMassIndex"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pRTh3HYkiDpZH83qB9wMAaKHXyiGI7iVhC8fic50yus"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:V_fDbUNnh1fvFKOiulWKg72jVDQCfgz_K6bIiMtzwBo"}],"meta":{"profile":["http://hl7.org/fhir/StructureDefinition/bmi","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg/m2","system":"http://unitsofmeasure.org","unit":"kg/m2","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyMassIndex/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMassIndex","unit":"count","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"39156-5","display":"Body mass index (BMI) [Ratio]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMassIndex"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pRTh3HYkiDpZH83qB9wMAaKHXyiGI7iVhC8fic50yus"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:V_fDbUNnh1fvFKOiulWKg72jVDQCfgz_K6bIiMtzwBo"}],"meta":{"profile":["http://hl7.org/fhir/StructureDefinition/bmi","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg/m2","system":"http://unitsofmeasure.org","unit":"kg/m2","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyMassIndex/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMassIndex","unit":"count","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"39156-5","display":"Body mass index (BMI) [Ratio]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMassIndex"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pRTh3HYkiDpZH83qB9wMAaKHXyiGI7iVhC8fic50yus"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:V_fDbUNnh1fvFKOiulWKg72jVDQCfgz_K6bIiMtzwBo"}],"meta":{"profile":["http://hl7.org/fhir/StructureDefinition/bmi","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg/m2","system":"http://unitsofmeasure.org","unit":"kg/m2","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyMassIndex/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMassIndex","unit":"count","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"39156-5","display":"Body mass index (BMI) [Ratio]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMassIndex"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pRTh3HYkiDpZH83qB9wMAaKHXyiGI7iVhC8fic50yus"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:V_fDbUNnh1fvFKOiulWKg72jVDQCfgz_K6bIiMtzwBo"}],"meta":{"profile":["http://hl7.org/fhir/StructureDefinition/bmi","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg/m2","system":"http://unitsofmeasure.org","unit":"kg/m2","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyMassIndex/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMassIndex","unit":"count","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"39156-5","display":"Body mass index (BMI) [Ratio]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMassIndex"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pRTh3HYkiDpZH83qB9wMAaKHXyiGI7iVhC8fic50yus"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:V_fDbUNnh1fvFKOiulWKg72jVDQCfgz_K6bIiMtzwBo"}],"meta":{"profile":["http://hl7.org/fhir/StructureDefinition/bmi","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg/m2","system":"http://unitsofmeasure.org","unit":"kg/m2","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyMassIndex/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMassIndex","unit":"count","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bodyMassIndex, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBodyMassIndex/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMassIndex","unit":"count","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bodyMassIndex, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBodyMassIndex/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMassIndex","unit":"count","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bodyMassIndex, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBodyTemperature/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyTemperature","unit":"degC","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8310-5","display":"Body temperature","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:JANtiO7naHME-7aVZxnGorhAfM2ENXSbc2xjFryPbss"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7MA8gm5QPkq1pyJ7H6M3OdjMBbRRabGwzTnF4dkIJWw"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-temperature","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyTemperature/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyTemperature","unit":"degC","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8310-5","display":"Body temperature","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:JANtiO7naHME-7aVZxnGorhAfM2ENXSbc2xjFryPbss"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7MA8gm5QPkq1pyJ7H6M3OdjMBbRRabGwzTnF4dkIJWw"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-temperature","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyTemperature/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyTemperature","unit":"degC","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8310-5","display":"Body temperature","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:JANtiO7naHME-7aVZxnGorhAfM2ENXSbc2xjFryPbss"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7MA8gm5QPkq1pyJ7H6M3OdjMBbRRabGwzTnF4dkIJWw"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-temperature","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyTemperature/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyTemperature","unit":"degC","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8310-5","display":"Body temperature","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:JANtiO7naHME-7aVZxnGorhAfM2ENXSbc2xjFryPbss"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7MA8gm5QPkq1pyJ7H6M3OdjMBbRRabGwzTnF4dkIJWw"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-temperature","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyTemperature/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyTemperature","unit":"degC","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8310-5","display":"Body temperature","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:JANtiO7naHME-7aVZxnGorhAfM2ENXSbc2xjFryPbss"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7MA8gm5QPkq1pyJ7H6M3OdjMBbRRabGwzTnF4dkIJWw"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-temperature","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyTemperature/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyTemperature","unit":"degC","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8310-5","display":"Body temperature","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:JANtiO7naHME-7aVZxnGorhAfM2ENXSbc2xjFryPbss"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7MA8gm5QPkq1pyJ7H6M3OdjMBbRRabGwzTnF4dkIJWw"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-temperature","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierBodyTemperature/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyTemperature","unit":"degC","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bodyTemperature, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBodyTemperature/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyTemperature","unit":"degC","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bodyTemperature, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierBodyTemperature/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyTemperature","unit":"degC","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bodyTemperature, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierCrossCountrySkiingSpeed/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCrossCountrySkiingSpeed","unit":"m/s","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCrossCountrySkiingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:l1h8ONTyZwWXkcIUC0hBMBCJz_bkAIM9YySAGBoGQyg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:DbFfKpTuGqzG1A1ya4uRsSp4zKpp0QcRRuCb2WFrqA0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCrossCountrySkiingSpeed/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCrossCountrySkiingSpeed","unit":"m/s","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCrossCountrySkiingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:l1h8ONTyZwWXkcIUC0hBMBCJz_bkAIM9YySAGBoGQyg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:DbFfKpTuGqzG1A1ya4uRsSp4zKpp0QcRRuCb2WFrqA0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCrossCountrySkiingSpeed/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCrossCountrySkiingSpeed","unit":"m/s","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCrossCountrySkiingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:l1h8ONTyZwWXkcIUC0hBMBCJz_bkAIM9YySAGBoGQyg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:DbFfKpTuGqzG1A1ya4uRsSp4zKpp0QcRRuCb2WFrqA0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCrossCountrySkiingSpeed/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCrossCountrySkiingSpeed","unit":"m/s","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCrossCountrySkiingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:l1h8ONTyZwWXkcIUC0hBMBCJz_bkAIM9YySAGBoGQyg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:DbFfKpTuGqzG1A1ya4uRsSp4zKpp0QcRRuCb2WFrqA0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCrossCountrySkiingSpeed/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCrossCountrySkiingSpeed","unit":"m/s","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCrossCountrySkiingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:l1h8ONTyZwWXkcIUC0hBMBCJz_bkAIM9YySAGBoGQyg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:DbFfKpTuGqzG1A1ya4uRsSp4zKpp0QcRRuCb2WFrqA0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCrossCountrySkiingSpeed/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCrossCountrySkiingSpeed","unit":"m/s","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCrossCountrySkiingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:l1h8ONTyZwWXkcIUC0hBMBCJz_bkAIM9YySAGBoGQyg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:DbFfKpTuGqzG1A1ya4uRsSp4zKpp0QcRRuCb2WFrqA0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCrossCountrySkiingSpeed/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCrossCountrySkiingSpeed","unit":"m/s","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.crossCountrySkiingSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierCrossCountrySkiingSpeed/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCrossCountrySkiingSpeed","unit":"m/s","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.crossCountrySkiingSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierCrossCountrySkiingSpeed/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCrossCountrySkiingSpeed","unit":"m/s","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.crossCountrySkiingSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingCadence/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingCadence","unit":"count/min","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"cycling-cadence","display":"Cycling cadence","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingCadence"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3riRgFgqs8NRu_JoCnO4fX6GkWzg8bFjxVdm8BoxAOE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7AJWSQgnF6nXT0iPe0XPML5H6r6CDVX4roENYy_b__I"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-cycling-cadence","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"revolutions/minute","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingCadence/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingCadence","unit":"count/min","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"cycling-cadence","display":"Cycling cadence","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingCadence"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3riRgFgqs8NRu_JoCnO4fX6GkWzg8bFjxVdm8BoxAOE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7AJWSQgnF6nXT0iPe0XPML5H6r6CDVX4roENYy_b__I"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-cycling-cadence","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"revolutions/minute","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingCadence/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingCadence","unit":"count/min","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"cycling-cadence","display":"Cycling cadence","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingCadence"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3riRgFgqs8NRu_JoCnO4fX6GkWzg8bFjxVdm8BoxAOE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7AJWSQgnF6nXT0iPe0XPML5H6r6CDVX4roENYy_b__I"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-cycling-cadence","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"revolutions/minute","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingCadence/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingCadence","unit":"count/min","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"cycling-cadence","display":"Cycling cadence","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingCadence"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3riRgFgqs8NRu_JoCnO4fX6GkWzg8bFjxVdm8BoxAOE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7AJWSQgnF6nXT0iPe0XPML5H6r6CDVX4roENYy_b__I"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-cycling-cadence","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"revolutions/minute","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingCadence/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingCadence","unit":"count/min","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"cycling-cadence","display":"Cycling cadence","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingCadence"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3riRgFgqs8NRu_JoCnO4fX6GkWzg8bFjxVdm8BoxAOE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7AJWSQgnF6nXT0iPe0XPML5H6r6CDVX4roENYy_b__I"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-cycling-cadence","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"revolutions/minute","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingCadence/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingCadence","unit":"count/min","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"cycling-cadence","display":"Cycling cadence","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingCadence"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3riRgFgqs8NRu_JoCnO4fX6GkWzg8bFjxVdm8BoxAOE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7AJWSQgnF6nXT0iPe0XPML5H6r6CDVX4roENYy_b__I"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-cycling-cadence","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"revolutions/minute","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingCadence/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingCadence","unit":"count/min","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.cyclingCadence, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingCadence/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingCadence","unit":"count/min","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.cyclingCadence, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingCadence/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingCadence","unit":"count/min","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.cyclingCadence, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingFunctionalThresholdPower/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingFunctionalThresholdPower","unit":"W","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"cycling-functional-threshold-power","display":"Cycling functional threshold power","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingFunctionalThresholdPower"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5PG_0U2YibSTbrFt-tLOI0UaxH88N-PQPOmn9UJcEYY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7D30lb2mmkAed-hNEqVypAZrjYHb7dyKmbmiIR170V8"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-cycling-functional-threshold-power"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"W","system":"http://unitsofmeasure.org","unit":"W","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingFunctionalThresholdPower/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingFunctionalThresholdPower","unit":"W","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"cycling-functional-threshold-power","display":"Cycling functional threshold power","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingFunctionalThresholdPower"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5PG_0U2YibSTbrFt-tLOI0UaxH88N-PQPOmn9UJcEYY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7D30lb2mmkAed-hNEqVypAZrjYHb7dyKmbmiIR170V8"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-cycling-functional-threshold-power"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"W","system":"http://unitsofmeasure.org","unit":"W","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingFunctionalThresholdPower/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingFunctionalThresholdPower","unit":"W","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"cycling-functional-threshold-power","display":"Cycling functional threshold power","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingFunctionalThresholdPower"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5PG_0U2YibSTbrFt-tLOI0UaxH88N-PQPOmn9UJcEYY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7D30lb2mmkAed-hNEqVypAZrjYHb7dyKmbmiIR170V8"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-cycling-functional-threshold-power"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"W","system":"http://unitsofmeasure.org","unit":"W","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingFunctionalThresholdPower/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingFunctionalThresholdPower","unit":"W","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"cycling-functional-threshold-power","display":"Cycling functional threshold power","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingFunctionalThresholdPower"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5PG_0U2YibSTbrFt-tLOI0UaxH88N-PQPOmn9UJcEYY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7D30lb2mmkAed-hNEqVypAZrjYHb7dyKmbmiIR170V8"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-cycling-functional-threshold-power"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"W","system":"http://unitsofmeasure.org","unit":"W","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingFunctionalThresholdPower/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingFunctionalThresholdPower","unit":"W","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"cycling-functional-threshold-power","display":"Cycling functional threshold power","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingFunctionalThresholdPower"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5PG_0U2YibSTbrFt-tLOI0UaxH88N-PQPOmn9UJcEYY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7D30lb2mmkAed-hNEqVypAZrjYHb7dyKmbmiIR170V8"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-cycling-functional-threshold-power"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"W","system":"http://unitsofmeasure.org","unit":"W","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingFunctionalThresholdPower/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingFunctionalThresholdPower","unit":"W","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"cycling-functional-threshold-power","display":"Cycling functional threshold power","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingFunctionalThresholdPower"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5PG_0U2YibSTbrFt-tLOI0UaxH88N-PQPOmn9UJcEYY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7D30lb2mmkAed-hNEqVypAZrjYHb7dyKmbmiIR170V8"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-cycling-functional-threshold-power"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"W","system":"http://unitsofmeasure.org","unit":"W","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingFunctionalThresholdPower/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingFunctionalThresholdPower","unit":"W","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.cyclingFunctionalThresholdPower, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingFunctionalThresholdPower/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingFunctionalThresholdPower","unit":"W","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.cyclingFunctionalThresholdPower, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingFunctionalThresholdPower/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingFunctionalThresholdPower","unit":"W","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.cyclingFunctionalThresholdPower, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingPower/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingPower","unit":"W","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"power","display":"Power","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingPower"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OI9YsGSTaqWTg2uNUf5atRnV2P4_82JU0KTzRMuO-wc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Xmz3zXpvEj8m8CIC-_ylBhpOzL1rVRJtEMnRnbBJ4n8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-power","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"W","system":"http://unitsofmeasure.org","unit":"W","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingPower/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingPower","unit":"W","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"power","display":"Power","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingPower"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OI9YsGSTaqWTg2uNUf5atRnV2P4_82JU0KTzRMuO-wc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Xmz3zXpvEj8m8CIC-_ylBhpOzL1rVRJtEMnRnbBJ4n8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-power","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"W","system":"http://unitsofmeasure.org","unit":"W","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingPower/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingPower","unit":"W","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"power","display":"Power","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingPower"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OI9YsGSTaqWTg2uNUf5atRnV2P4_82JU0KTzRMuO-wc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Xmz3zXpvEj8m8CIC-_ylBhpOzL1rVRJtEMnRnbBJ4n8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-power","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"W","system":"http://unitsofmeasure.org","unit":"W","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingPower/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingPower","unit":"W","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"power","display":"Power","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingPower"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OI9YsGSTaqWTg2uNUf5atRnV2P4_82JU0KTzRMuO-wc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Xmz3zXpvEj8m8CIC-_ylBhpOzL1rVRJtEMnRnbBJ4n8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-power","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"W","system":"http://unitsofmeasure.org","unit":"W","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingPower/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingPower","unit":"W","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"power","display":"Power","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingPower"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OI9YsGSTaqWTg2uNUf5atRnV2P4_82JU0KTzRMuO-wc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Xmz3zXpvEj8m8CIC-_ylBhpOzL1rVRJtEMnRnbBJ4n8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-power","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"W","system":"http://unitsofmeasure.org","unit":"W","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingPower/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingPower","unit":"W","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"power","display":"Power","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingPower"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OI9YsGSTaqWTg2uNUf5atRnV2P4_82JU0KTzRMuO-wc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Xmz3zXpvEj8m8CIC-_ylBhpOzL1rVRJtEMnRnbBJ4n8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-power","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"W","system":"http://unitsofmeasure.org","unit":"W","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingPower/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingPower","unit":"W","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.cyclingPower, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingPower/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingPower","unit":"W","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.cyclingPower, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingPower/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingPower","unit":"W","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.cyclingPower, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingSpeed/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingSpeed","unit":"m/s","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:o3xVIWVHtGJHMRJRfXmslTVAj373nCqRO9cGXpmvmQ8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Z4Aw8UiFKNnQoiocmqYT20bUamrkikdLhmP85Oae_DU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingSpeed/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingSpeed","unit":"m/s","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:o3xVIWVHtGJHMRJRfXmslTVAj373nCqRO9cGXpmvmQ8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Z4Aw8UiFKNnQoiocmqYT20bUamrkikdLhmP85Oae_DU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingSpeed/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingSpeed","unit":"m/s","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:o3xVIWVHtGJHMRJRfXmslTVAj373nCqRO9cGXpmvmQ8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Z4Aw8UiFKNnQoiocmqYT20bUamrkikdLhmP85Oae_DU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingSpeed/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingSpeed","unit":"m/s","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:o3xVIWVHtGJHMRJRfXmslTVAj373nCqRO9cGXpmvmQ8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Z4Aw8UiFKNnQoiocmqYT20bUamrkikdLhmP85Oae_DU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingSpeed/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingSpeed","unit":"m/s","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:o3xVIWVHtGJHMRJRfXmslTVAj373nCqRO9cGXpmvmQ8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Z4Aw8UiFKNnQoiocmqYT20bUamrkikdLhmP85Oae_DU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingSpeed/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingSpeed","unit":"m/s","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierCyclingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:o3xVIWVHtGJHMRJRfXmslTVAj373nCqRO9cGXpmvmQ8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Z4Aw8UiFKNnQoiocmqYT20bUamrkikdLhmP85Oae_DU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingSpeed/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingSpeed","unit":"m/s","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.cyclingSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingSpeed/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingSpeed","unit":"m/s","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.cyclingSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierCyclingSpeed/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierCyclingSpeed","unit":"m/s","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.cyclingSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryBiotin/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryBiotin","unit":"mcg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-biotin","display":"Dietary biotin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryBiotin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zCHYkW3DbDv4wB3UxKJy3N4yk9hAw8JHHOc0zpCqMzQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:EE0hL53Pij2ifImJviWLqNqgFwsrmKcWeD4rG_2vfZI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-biotin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryBiotin/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryBiotin","unit":"mcg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-biotin","display":"Dietary biotin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryBiotin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zCHYkW3DbDv4wB3UxKJy3N4yk9hAw8JHHOc0zpCqMzQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:EE0hL53Pij2ifImJviWLqNqgFwsrmKcWeD4rG_2vfZI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-biotin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryBiotin/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryBiotin","unit":"mcg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-biotin","display":"Dietary biotin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryBiotin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zCHYkW3DbDv4wB3UxKJy3N4yk9hAw8JHHOc0zpCqMzQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:EE0hL53Pij2ifImJviWLqNqgFwsrmKcWeD4rG_2vfZI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-biotin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryBiotin/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryBiotin","unit":"mcg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-biotin","display":"Dietary biotin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryBiotin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zCHYkW3DbDv4wB3UxKJy3N4yk9hAw8JHHOc0zpCqMzQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:EE0hL53Pij2ifImJviWLqNqgFwsrmKcWeD4rG_2vfZI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-biotin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryBiotin/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryBiotin","unit":"mcg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-biotin","display":"Dietary biotin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryBiotin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zCHYkW3DbDv4wB3UxKJy3N4yk9hAw8JHHOc0zpCqMzQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:EE0hL53Pij2ifImJviWLqNqgFwsrmKcWeD4rG_2vfZI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-biotin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryBiotin/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryBiotin","unit":"mcg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-biotin","display":"Dietary biotin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryBiotin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zCHYkW3DbDv4wB3UxKJy3N4yk9hAw8JHHOc0zpCqMzQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:EE0hL53Pij2ifImJviWLqNqgFwsrmKcWeD4rG_2vfZI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-biotin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryBiotin/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryBiotin","unit":"mcg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryBiotin, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryBiotin/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryBiotin","unit":"mcg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryBiotin, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryBiotin/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryBiotin","unit":"mcg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryBiotin, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCaffeine/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCaffeine","unit":"mg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-caffeine","display":"Dietary caffeine","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCaffeine"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:A7GpP_YM8P7QESPlFLOFFSBBFaQNAQ_k3TwcOvhoXGw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vA6Ji9m7KOhKcVnUY3Sq_3jLmxLOt4ZnRWoFoTvCTig"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-caffeine","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCaffeine/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCaffeine","unit":"mg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-caffeine","display":"Dietary caffeine","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCaffeine"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:A7GpP_YM8P7QESPlFLOFFSBBFaQNAQ_k3TwcOvhoXGw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vA6Ji9m7KOhKcVnUY3Sq_3jLmxLOt4ZnRWoFoTvCTig"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-caffeine","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCaffeine/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCaffeine","unit":"mg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-caffeine","display":"Dietary caffeine","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCaffeine"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:A7GpP_YM8P7QESPlFLOFFSBBFaQNAQ_k3TwcOvhoXGw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vA6Ji9m7KOhKcVnUY3Sq_3jLmxLOt4ZnRWoFoTvCTig"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-caffeine","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCaffeine/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCaffeine","unit":"mg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-caffeine","display":"Dietary caffeine","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCaffeine"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:A7GpP_YM8P7QESPlFLOFFSBBFaQNAQ_k3TwcOvhoXGw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vA6Ji9m7KOhKcVnUY3Sq_3jLmxLOt4ZnRWoFoTvCTig"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-caffeine","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCaffeine/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCaffeine","unit":"mg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-caffeine","display":"Dietary caffeine","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCaffeine"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:A7GpP_YM8P7QESPlFLOFFSBBFaQNAQ_k3TwcOvhoXGw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vA6Ji9m7KOhKcVnUY3Sq_3jLmxLOt4ZnRWoFoTvCTig"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-caffeine","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCaffeine/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCaffeine","unit":"mg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-caffeine","display":"Dietary caffeine","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCaffeine"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:A7GpP_YM8P7QESPlFLOFFSBBFaQNAQ_k3TwcOvhoXGw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vA6Ji9m7KOhKcVnUY3Sq_3jLmxLOt4ZnRWoFoTvCTig"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-caffeine","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCaffeine/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCaffeine","unit":"mg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryCaffeine, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCaffeine/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCaffeine","unit":"mg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryCaffeine, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCaffeine/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCaffeine","unit":"mg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryCaffeine, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCalcium/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCalcium","unit":"mg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-calcium","display":"Dietary calcium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCalcium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OZoYnK_X9WEmrqKuEA5gzzpRlcOnXnXasz2pLsXXIDI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:i8XeJGI-NmQK2vP5QcUicHFShhhuChAvc14k0hsVO44"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-calcium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCalcium/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCalcium","unit":"mg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-calcium","display":"Dietary calcium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCalcium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OZoYnK_X9WEmrqKuEA5gzzpRlcOnXnXasz2pLsXXIDI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:i8XeJGI-NmQK2vP5QcUicHFShhhuChAvc14k0hsVO44"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-calcium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCalcium/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCalcium","unit":"mg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-calcium","display":"Dietary calcium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCalcium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OZoYnK_X9WEmrqKuEA5gzzpRlcOnXnXasz2pLsXXIDI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:i8XeJGI-NmQK2vP5QcUicHFShhhuChAvc14k0hsVO44"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-calcium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCalcium/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCalcium","unit":"mg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-calcium","display":"Dietary calcium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCalcium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OZoYnK_X9WEmrqKuEA5gzzpRlcOnXnXasz2pLsXXIDI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:i8XeJGI-NmQK2vP5QcUicHFShhhuChAvc14k0hsVO44"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-calcium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCalcium/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCalcium","unit":"mg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-calcium","display":"Dietary calcium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCalcium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OZoYnK_X9WEmrqKuEA5gzzpRlcOnXnXasz2pLsXXIDI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:i8XeJGI-NmQK2vP5QcUicHFShhhuChAvc14k0hsVO44"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-calcium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCalcium/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCalcium","unit":"mg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-calcium","display":"Dietary calcium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCalcium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OZoYnK_X9WEmrqKuEA5gzzpRlcOnXnXasz2pLsXXIDI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:i8XeJGI-NmQK2vP5QcUicHFShhhuChAvc14k0hsVO44"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-calcium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCalcium/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCalcium","unit":"mg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryCalcium, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCalcium/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCalcium","unit":"mg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryCalcium, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCalcium/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCalcium","unit":"mg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryCalcium, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCarbohydrates/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCarbohydrates","unit":"g","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9060-5","display":"Carbohydrate intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCarbohydrates"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YBfzWeQaUT4JiZe17zuFyxNfggjCEdyqtTwwwAo2YF8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:umuJToEIwrMJfL2hgkz3Q1fYvDZgf0jdIVQHmSfNYN4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-carbohydrates","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCarbohydrates/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCarbohydrates","unit":"g","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9060-5","display":"Carbohydrate intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCarbohydrates"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YBfzWeQaUT4JiZe17zuFyxNfggjCEdyqtTwwwAo2YF8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:umuJToEIwrMJfL2hgkz3Q1fYvDZgf0jdIVQHmSfNYN4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-carbohydrates","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCarbohydrates/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCarbohydrates","unit":"g","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9060-5","display":"Carbohydrate intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCarbohydrates"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YBfzWeQaUT4JiZe17zuFyxNfggjCEdyqtTwwwAo2YF8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:umuJToEIwrMJfL2hgkz3Q1fYvDZgf0jdIVQHmSfNYN4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-carbohydrates","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCarbohydrates/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCarbohydrates","unit":"g","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9060-5","display":"Carbohydrate intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCarbohydrates"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YBfzWeQaUT4JiZe17zuFyxNfggjCEdyqtTwwwAo2YF8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:umuJToEIwrMJfL2hgkz3Q1fYvDZgf0jdIVQHmSfNYN4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-carbohydrates","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCarbohydrates/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCarbohydrates","unit":"g","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9060-5","display":"Carbohydrate intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCarbohydrates"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YBfzWeQaUT4JiZe17zuFyxNfggjCEdyqtTwwwAo2YF8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:umuJToEIwrMJfL2hgkz3Q1fYvDZgf0jdIVQHmSfNYN4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-carbohydrates","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCarbohydrates/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCarbohydrates","unit":"g","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9060-5","display":"Carbohydrate intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCarbohydrates"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YBfzWeQaUT4JiZe17zuFyxNfggjCEdyqtTwwwAo2YF8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:umuJToEIwrMJfL2hgkz3Q1fYvDZgf0jdIVQHmSfNYN4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-carbohydrates","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCarbohydrates/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCarbohydrates","unit":"g","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryCarbohydrates, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCarbohydrates/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCarbohydrates","unit":"g","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryCarbohydrates, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCarbohydrates/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCarbohydrates","unit":"g","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryCarbohydrates, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryChloride/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryChloride","unit":"mg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-chloride","display":"Dietary chloride","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryChloride"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:sV9rTh2nF35m_aaV9Ko0fkzSf1Dr4Z6xmmsA4Px7fSo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WdRmU6DTaXqeknrK1-r043vhXAbkhzs9JDpUgYPecN8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-chloride","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryChloride/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryChloride","unit":"mg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-chloride","display":"Dietary chloride","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryChloride"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:sV9rTh2nF35m_aaV9Ko0fkzSf1Dr4Z6xmmsA4Px7fSo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WdRmU6DTaXqeknrK1-r043vhXAbkhzs9JDpUgYPecN8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-chloride","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryChloride/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryChloride","unit":"mg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-chloride","display":"Dietary chloride","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryChloride"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:sV9rTh2nF35m_aaV9Ko0fkzSf1Dr4Z6xmmsA4Px7fSo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WdRmU6DTaXqeknrK1-r043vhXAbkhzs9JDpUgYPecN8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-chloride","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryChloride/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryChloride","unit":"mg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-chloride","display":"Dietary chloride","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryChloride"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:sV9rTh2nF35m_aaV9Ko0fkzSf1Dr4Z6xmmsA4Px7fSo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WdRmU6DTaXqeknrK1-r043vhXAbkhzs9JDpUgYPecN8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-chloride","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryChloride/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryChloride","unit":"mg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-chloride","display":"Dietary chloride","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryChloride"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:sV9rTh2nF35m_aaV9Ko0fkzSf1Dr4Z6xmmsA4Px7fSo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WdRmU6DTaXqeknrK1-r043vhXAbkhzs9JDpUgYPecN8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-chloride","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryChloride/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryChloride","unit":"mg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-chloride","display":"Dietary chloride","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryChloride"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:sV9rTh2nF35m_aaV9Ko0fkzSf1Dr4Z6xmmsA4Px7fSo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WdRmU6DTaXqeknrK1-r043vhXAbkhzs9JDpUgYPecN8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-chloride","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryChloride/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryChloride","unit":"mg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryChloride, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryChloride/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryChloride","unit":"mg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryChloride, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryChloride/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryChloride","unit":"mg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryChloride, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCholesterol/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCholesterol","unit":"mg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-cholesterol","display":"Dietary cholesterol","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCholesterol"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:h5NxIMSchaL_D1rmYUzg9Vg8s1mS5D8ixllXUoRgiKo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OrYj4chKZ5k30B548f8eqmAhySq-VMn87n3GKpaCjlM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-cholesterol","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCholesterol/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCholesterol","unit":"mg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-cholesterol","display":"Dietary cholesterol","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCholesterol"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:h5NxIMSchaL_D1rmYUzg9Vg8s1mS5D8ixllXUoRgiKo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OrYj4chKZ5k30B548f8eqmAhySq-VMn87n3GKpaCjlM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-cholesterol","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCholesterol/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCholesterol","unit":"mg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-cholesterol","display":"Dietary cholesterol","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCholesterol"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:h5NxIMSchaL_D1rmYUzg9Vg8s1mS5D8ixllXUoRgiKo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OrYj4chKZ5k30B548f8eqmAhySq-VMn87n3GKpaCjlM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-cholesterol","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCholesterol/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCholesterol","unit":"mg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-cholesterol","display":"Dietary cholesterol","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCholesterol"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:h5NxIMSchaL_D1rmYUzg9Vg8s1mS5D8ixllXUoRgiKo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OrYj4chKZ5k30B548f8eqmAhySq-VMn87n3GKpaCjlM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-cholesterol","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCholesterol/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCholesterol","unit":"mg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-cholesterol","display":"Dietary cholesterol","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCholesterol"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:h5NxIMSchaL_D1rmYUzg9Vg8s1mS5D8ixllXUoRgiKo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OrYj4chKZ5k30B548f8eqmAhySq-VMn87n3GKpaCjlM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-cholesterol","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCholesterol/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCholesterol","unit":"mg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-cholesterol","display":"Dietary cholesterol","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCholesterol"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:h5NxIMSchaL_D1rmYUzg9Vg8s1mS5D8ixllXUoRgiKo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OrYj4chKZ5k30B548f8eqmAhySq-VMn87n3GKpaCjlM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-cholesterol","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCholesterol/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCholesterol","unit":"mg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryCholesterol, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCholesterol/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCholesterol","unit":"mg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryCholesterol, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCholesterol/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCholesterol","unit":"mg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryCholesterol, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryChromium/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryChromium","unit":"mcg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-chromium","display":"Dietary chromium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryChromium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jZi6P7oQ1IdaJ07cDi4T9HuNwh5g8_92oym3Ce8F7fc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1bE2gFvJOQJ8Jnlu3Qi4UnYe5X3XsCFxyxVBVS-J8Ac"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-chromium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryChromium/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryChromium","unit":"mcg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-chromium","display":"Dietary chromium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryChromium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jZi6P7oQ1IdaJ07cDi4T9HuNwh5g8_92oym3Ce8F7fc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1bE2gFvJOQJ8Jnlu3Qi4UnYe5X3XsCFxyxVBVS-J8Ac"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-chromium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryChromium/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryChromium","unit":"mcg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-chromium","display":"Dietary chromium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryChromium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jZi6P7oQ1IdaJ07cDi4T9HuNwh5g8_92oym3Ce8F7fc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1bE2gFvJOQJ8Jnlu3Qi4UnYe5X3XsCFxyxVBVS-J8Ac"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-chromium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryChromium/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryChromium","unit":"mcg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-chromium","display":"Dietary chromium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryChromium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jZi6P7oQ1IdaJ07cDi4T9HuNwh5g8_92oym3Ce8F7fc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1bE2gFvJOQJ8Jnlu3Qi4UnYe5X3XsCFxyxVBVS-J8Ac"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-chromium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryChromium/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryChromium","unit":"mcg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-chromium","display":"Dietary chromium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryChromium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jZi6P7oQ1IdaJ07cDi4T9HuNwh5g8_92oym3Ce8F7fc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1bE2gFvJOQJ8Jnlu3Qi4UnYe5X3XsCFxyxVBVS-J8Ac"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-chromium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryChromium/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryChromium","unit":"mcg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-chromium","display":"Dietary chromium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryChromium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jZi6P7oQ1IdaJ07cDi4T9HuNwh5g8_92oym3Ce8F7fc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1bE2gFvJOQJ8Jnlu3Qi4UnYe5X3XsCFxyxVBVS-J8Ac"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-chromium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryChromium/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryChromium","unit":"mcg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryChromium, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryChromium/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryChromium","unit":"mcg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryChromium, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryChromium/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryChromium","unit":"mcg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryChromium, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCopper/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCopper","unit":"mcg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-copper","display":"Dietary copper","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCopper"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ekpwwfy_9rbxLhIn5jxhqdfadT00yrZt0KZI-ADsa0Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2WUIfWJ9_hLyKI9WkesFZwx8sCtXqoRH65bkpeWM7_Q"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-copper","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCopper/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCopper","unit":"mcg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-copper","display":"Dietary copper","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCopper"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ekpwwfy_9rbxLhIn5jxhqdfadT00yrZt0KZI-ADsa0Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2WUIfWJ9_hLyKI9WkesFZwx8sCtXqoRH65bkpeWM7_Q"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-copper","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCopper/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCopper","unit":"mcg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-copper","display":"Dietary copper","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCopper"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ekpwwfy_9rbxLhIn5jxhqdfadT00yrZt0KZI-ADsa0Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2WUIfWJ9_hLyKI9WkesFZwx8sCtXqoRH65bkpeWM7_Q"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-copper","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCopper/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCopper","unit":"mcg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-copper","display":"Dietary copper","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCopper"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ekpwwfy_9rbxLhIn5jxhqdfadT00yrZt0KZI-ADsa0Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2WUIfWJ9_hLyKI9WkesFZwx8sCtXqoRH65bkpeWM7_Q"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-copper","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCopper/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCopper","unit":"mcg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-copper","display":"Dietary copper","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCopper"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ekpwwfy_9rbxLhIn5jxhqdfadT00yrZt0KZI-ADsa0Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2WUIfWJ9_hLyKI9WkesFZwx8sCtXqoRH65bkpeWM7_Q"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-copper","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCopper/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCopper","unit":"mcg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-copper","display":"Dietary copper","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryCopper"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ekpwwfy_9rbxLhIn5jxhqdfadT00yrZt0KZI-ADsa0Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2WUIfWJ9_hLyKI9WkesFZwx8sCtXqoRH65bkpeWM7_Q"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-copper","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCopper/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCopper","unit":"mcg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryCopper, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCopper/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCopper","unit":"mcg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryCopper, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryCopper/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryCopper","unit":"mcg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryCopper, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryEnergyConsumed/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryEnergyConsumed/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryEnergyConsumed/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryEnergyConsumed/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryEnergyConsumed/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryEnergyConsumed/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryEnergyConsumed/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryEnergyConsumed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryEnergyConsumed/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryEnergyConsumed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryEnergyConsumed/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryEnergyConsumed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatMonounsaturated/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatMonounsaturated","unit":"g","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fat-monounsaturated","display":"Dietary monounsaturated fat","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatMonounsaturated"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2xogwTpuZKt43wWvTtUMiyjMwPZIvLPvYTRPSl0CuS4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wgAGnZb5ri1F9MeRbocbVCJxBrQbUXPHaF13PygVGes"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-monounsaturated","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatMonounsaturated/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatMonounsaturated","unit":"g","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fat-monounsaturated","display":"Dietary monounsaturated fat","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatMonounsaturated"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2xogwTpuZKt43wWvTtUMiyjMwPZIvLPvYTRPSl0CuS4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wgAGnZb5ri1F9MeRbocbVCJxBrQbUXPHaF13PygVGes"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-monounsaturated","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatMonounsaturated/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatMonounsaturated","unit":"g","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fat-monounsaturated","display":"Dietary monounsaturated fat","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatMonounsaturated"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2xogwTpuZKt43wWvTtUMiyjMwPZIvLPvYTRPSl0CuS4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wgAGnZb5ri1F9MeRbocbVCJxBrQbUXPHaF13PygVGes"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-monounsaturated","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatMonounsaturated/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatMonounsaturated","unit":"g","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fat-monounsaturated","display":"Dietary monounsaturated fat","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatMonounsaturated"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2xogwTpuZKt43wWvTtUMiyjMwPZIvLPvYTRPSl0CuS4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wgAGnZb5ri1F9MeRbocbVCJxBrQbUXPHaF13PygVGes"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-monounsaturated","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatMonounsaturated/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatMonounsaturated","unit":"g","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fat-monounsaturated","display":"Dietary monounsaturated fat","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatMonounsaturated"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2xogwTpuZKt43wWvTtUMiyjMwPZIvLPvYTRPSl0CuS4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wgAGnZb5ri1F9MeRbocbVCJxBrQbUXPHaF13PygVGes"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-monounsaturated","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatMonounsaturated/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatMonounsaturated","unit":"g","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fat-monounsaturated","display":"Dietary monounsaturated fat","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatMonounsaturated"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2xogwTpuZKt43wWvTtUMiyjMwPZIvLPvYTRPSl0CuS4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wgAGnZb5ri1F9MeRbocbVCJxBrQbUXPHaF13PygVGes"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-monounsaturated","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatMonounsaturated/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatMonounsaturated","unit":"g","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryFatMonounsaturated, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatMonounsaturated/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatMonounsaturated","unit":"g","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryFatMonounsaturated, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatMonounsaturated/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatMonounsaturated","unit":"g","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryFatMonounsaturated, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatPolyunsaturated/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatPolyunsaturated","unit":"g","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fat-polyunsaturated","display":"Dietary polyunsaturated fat","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatPolyunsaturated"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:c9N58Ldpv8gPr6b3SMJkd8mc292cYnuHln7iSNxi8Wk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qUUnh4OWxwGkfm4lcrTV1rAsLVym5iTlpn-foABAvuo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-polyunsaturated","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatPolyunsaturated/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatPolyunsaturated","unit":"g","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fat-polyunsaturated","display":"Dietary polyunsaturated fat","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatPolyunsaturated"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:c9N58Ldpv8gPr6b3SMJkd8mc292cYnuHln7iSNxi8Wk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qUUnh4OWxwGkfm4lcrTV1rAsLVym5iTlpn-foABAvuo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-polyunsaturated","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatPolyunsaturated/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatPolyunsaturated","unit":"g","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fat-polyunsaturated","display":"Dietary polyunsaturated fat","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatPolyunsaturated"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:c9N58Ldpv8gPr6b3SMJkd8mc292cYnuHln7iSNxi8Wk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qUUnh4OWxwGkfm4lcrTV1rAsLVym5iTlpn-foABAvuo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-polyunsaturated","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatPolyunsaturated/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatPolyunsaturated","unit":"g","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fat-polyunsaturated","display":"Dietary polyunsaturated fat","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatPolyunsaturated"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:c9N58Ldpv8gPr6b3SMJkd8mc292cYnuHln7iSNxi8Wk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qUUnh4OWxwGkfm4lcrTV1rAsLVym5iTlpn-foABAvuo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-polyunsaturated","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatPolyunsaturated/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatPolyunsaturated","unit":"g","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fat-polyunsaturated","display":"Dietary polyunsaturated fat","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatPolyunsaturated"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:c9N58Ldpv8gPr6b3SMJkd8mc292cYnuHln7iSNxi8Wk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qUUnh4OWxwGkfm4lcrTV1rAsLVym5iTlpn-foABAvuo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-polyunsaturated","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatPolyunsaturated/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatPolyunsaturated","unit":"g","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fat-polyunsaturated","display":"Dietary polyunsaturated fat","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatPolyunsaturated"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:c9N58Ldpv8gPr6b3SMJkd8mc292cYnuHln7iSNxi8Wk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qUUnh4OWxwGkfm4lcrTV1rAsLVym5iTlpn-foABAvuo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-polyunsaturated","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatPolyunsaturated/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatPolyunsaturated","unit":"g","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryFatPolyunsaturated, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatPolyunsaturated/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatPolyunsaturated","unit":"g","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryFatPolyunsaturated, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatPolyunsaturated/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatPolyunsaturated","unit":"g","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryFatPolyunsaturated, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatSaturated/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatSaturated","unit":"g","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fat-saturated","display":"Dietary saturated fat","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatSaturated"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:hG3qxHzZzbsUTMdBF9KV_ONexLmYwsqe1gJ0FEt5ezg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-rySxSiWAQC3w2uENHvOpVNsZ1UjBHNB24ge62IjPK0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-saturated","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatSaturated/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatSaturated","unit":"g","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fat-saturated","display":"Dietary saturated fat","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatSaturated"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:hG3qxHzZzbsUTMdBF9KV_ONexLmYwsqe1gJ0FEt5ezg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-rySxSiWAQC3w2uENHvOpVNsZ1UjBHNB24ge62IjPK0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-saturated","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatSaturated/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatSaturated","unit":"g","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fat-saturated","display":"Dietary saturated fat","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatSaturated"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:hG3qxHzZzbsUTMdBF9KV_ONexLmYwsqe1gJ0FEt5ezg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-rySxSiWAQC3w2uENHvOpVNsZ1UjBHNB24ge62IjPK0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-saturated","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatSaturated/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatSaturated","unit":"g","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fat-saturated","display":"Dietary saturated fat","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatSaturated"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:hG3qxHzZzbsUTMdBF9KV_ONexLmYwsqe1gJ0FEt5ezg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-rySxSiWAQC3w2uENHvOpVNsZ1UjBHNB24ge62IjPK0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-saturated","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatSaturated/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatSaturated","unit":"g","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fat-saturated","display":"Dietary saturated fat","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatSaturated"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:hG3qxHzZzbsUTMdBF9KV_ONexLmYwsqe1gJ0FEt5ezg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-rySxSiWAQC3w2uENHvOpVNsZ1UjBHNB24ge62IjPK0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-saturated","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatSaturated/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatSaturated","unit":"g","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fat-saturated","display":"Dietary saturated fat","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatSaturated"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:hG3qxHzZzbsUTMdBF9KV_ONexLmYwsqe1gJ0FEt5ezg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-rySxSiWAQC3w2uENHvOpVNsZ1UjBHNB24ge62IjPK0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-saturated","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatSaturated/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatSaturated","unit":"g","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryFatSaturated, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatSaturated/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatSaturated","unit":"g","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryFatSaturated, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatSaturated/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatSaturated","unit":"g","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryFatSaturated, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatTotal/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatTotal","unit":"g","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9067-0","display":"Fat intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatTotal"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yfYH8Gh0ayBqcdPBazeI91PcD4bMAroXPKe8jthMyko"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BHes2Iosm1XXHwLyZwwlXWqKxwkoYG1NemK6TgKTbsc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-total","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatTotal/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatTotal","unit":"g","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9067-0","display":"Fat intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatTotal"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yfYH8Gh0ayBqcdPBazeI91PcD4bMAroXPKe8jthMyko"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BHes2Iosm1XXHwLyZwwlXWqKxwkoYG1NemK6TgKTbsc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-total","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatTotal/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatTotal","unit":"g","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9067-0","display":"Fat intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatTotal"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yfYH8Gh0ayBqcdPBazeI91PcD4bMAroXPKe8jthMyko"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BHes2Iosm1XXHwLyZwwlXWqKxwkoYG1NemK6TgKTbsc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-total","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatTotal/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatTotal","unit":"g","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9067-0","display":"Fat intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatTotal"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yfYH8Gh0ayBqcdPBazeI91PcD4bMAroXPKe8jthMyko"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BHes2Iosm1XXHwLyZwwlXWqKxwkoYG1NemK6TgKTbsc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-total","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatTotal/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatTotal","unit":"g","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9067-0","display":"Fat intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatTotal"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yfYH8Gh0ayBqcdPBazeI91PcD4bMAroXPKe8jthMyko"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BHes2Iosm1XXHwLyZwwlXWqKxwkoYG1NemK6TgKTbsc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-total","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatTotal/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatTotal","unit":"g","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9067-0","display":"Fat intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFatTotal"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yfYH8Gh0ayBqcdPBazeI91PcD4bMAroXPKe8jthMyko"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BHes2Iosm1XXHwLyZwwlXWqKxwkoYG1NemK6TgKTbsc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-total","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatTotal/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatTotal","unit":"g","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryFatTotal, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatTotal/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatTotal","unit":"g","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryFatTotal, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFatTotal/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFatTotal","unit":"g","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryFatTotal, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFiber/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFiber","unit":"g","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fiber","display":"Dietary fiber","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFiber"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ANov0VB1Q4zzoVKgd-ctxmZbvnjZk3eOcrV9J5-nSAs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qwCgbha1T7QPNoMPo3V5QbQxjB1lSkt131YBR4hmoRc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fiber","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFiber/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFiber","unit":"g","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fiber","display":"Dietary fiber","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFiber"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ANov0VB1Q4zzoVKgd-ctxmZbvnjZk3eOcrV9J5-nSAs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qwCgbha1T7QPNoMPo3V5QbQxjB1lSkt131YBR4hmoRc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fiber","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFiber/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFiber","unit":"g","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fiber","display":"Dietary fiber","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFiber"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ANov0VB1Q4zzoVKgd-ctxmZbvnjZk3eOcrV9J5-nSAs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qwCgbha1T7QPNoMPo3V5QbQxjB1lSkt131YBR4hmoRc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fiber","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFiber/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFiber","unit":"g","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fiber","display":"Dietary fiber","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFiber"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ANov0VB1Q4zzoVKgd-ctxmZbvnjZk3eOcrV9J5-nSAs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qwCgbha1T7QPNoMPo3V5QbQxjB1lSkt131YBR4hmoRc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fiber","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFiber/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFiber","unit":"g","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fiber","display":"Dietary fiber","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFiber"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ANov0VB1Q4zzoVKgd-ctxmZbvnjZk3eOcrV9J5-nSAs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qwCgbha1T7QPNoMPo3V5QbQxjB1lSkt131YBR4hmoRc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fiber","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFiber/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFiber","unit":"g","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-fiber","display":"Dietary fiber","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFiber"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ANov0VB1Q4zzoVKgd-ctxmZbvnjZk3eOcrV9J5-nSAs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qwCgbha1T7QPNoMPo3V5QbQxjB1lSkt131YBR4hmoRc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fiber","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFiber/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFiber","unit":"g","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryFiber, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFiber/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFiber","unit":"g","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryFiber, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFiber/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFiber","unit":"g","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryFiber, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFolate/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFolate","unit":"mcg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-folate","display":"Dietary folate","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFolate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:S_o-v6PGIM_yA9eGVqPzG1taE5FqBq0inTj2aMzz-uY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_ZnxoxZoCcbTjkN8nCwQ3AKKYqePO5_qoD24Y1Svfmk"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-folate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFolate/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFolate","unit":"mcg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-folate","display":"Dietary folate","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFolate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:S_o-v6PGIM_yA9eGVqPzG1taE5FqBq0inTj2aMzz-uY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_ZnxoxZoCcbTjkN8nCwQ3AKKYqePO5_qoD24Y1Svfmk"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-folate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFolate/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFolate","unit":"mcg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-folate","display":"Dietary folate","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFolate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:S_o-v6PGIM_yA9eGVqPzG1taE5FqBq0inTj2aMzz-uY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_ZnxoxZoCcbTjkN8nCwQ3AKKYqePO5_qoD24Y1Svfmk"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-folate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFolate/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFolate","unit":"mcg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-folate","display":"Dietary folate","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFolate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:S_o-v6PGIM_yA9eGVqPzG1taE5FqBq0inTj2aMzz-uY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_ZnxoxZoCcbTjkN8nCwQ3AKKYqePO5_qoD24Y1Svfmk"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-folate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFolate/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFolate","unit":"mcg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-folate","display":"Dietary folate","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFolate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:S_o-v6PGIM_yA9eGVqPzG1taE5FqBq0inTj2aMzz-uY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_ZnxoxZoCcbTjkN8nCwQ3AKKYqePO5_qoD24Y1Svfmk"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-folate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFolate/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFolate","unit":"mcg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-folate","display":"Dietary folate","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryFolate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:S_o-v6PGIM_yA9eGVqPzG1taE5FqBq0inTj2aMzz-uY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_ZnxoxZoCcbTjkN8nCwQ3AKKYqePO5_qoD24Y1Svfmk"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-folate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFolate/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFolate","unit":"mcg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryFolate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFolate/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFolate","unit":"mcg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryFolate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryFolate/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryFolate","unit":"mcg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryFolate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryIodine/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryIodine","unit":"mcg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-iodine","display":"Dietary iodine","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryIodine"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:UXqzLlS-Hjw0L7tImzNPLMNmE6HrDjobgeWPFev7Gvk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pb9pAIslNgMrTxuMHtYwKXZXxzO4TchevB-VVOOtcdw"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-iodine","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryIodine/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryIodine","unit":"mcg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-iodine","display":"Dietary iodine","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryIodine"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:UXqzLlS-Hjw0L7tImzNPLMNmE6HrDjobgeWPFev7Gvk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pb9pAIslNgMrTxuMHtYwKXZXxzO4TchevB-VVOOtcdw"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-iodine","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryIodine/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryIodine","unit":"mcg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-iodine","display":"Dietary iodine","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryIodine"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:UXqzLlS-Hjw0L7tImzNPLMNmE6HrDjobgeWPFev7Gvk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pb9pAIslNgMrTxuMHtYwKXZXxzO4TchevB-VVOOtcdw"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-iodine","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryIodine/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryIodine","unit":"mcg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-iodine","display":"Dietary iodine","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryIodine"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:UXqzLlS-Hjw0L7tImzNPLMNmE6HrDjobgeWPFev7Gvk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pb9pAIslNgMrTxuMHtYwKXZXxzO4TchevB-VVOOtcdw"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-iodine","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryIodine/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryIodine","unit":"mcg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-iodine","display":"Dietary iodine","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryIodine"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:UXqzLlS-Hjw0L7tImzNPLMNmE6HrDjobgeWPFev7Gvk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pb9pAIslNgMrTxuMHtYwKXZXxzO4TchevB-VVOOtcdw"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-iodine","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryIodine/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryIodine","unit":"mcg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-iodine","display":"Dietary iodine","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryIodine"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:UXqzLlS-Hjw0L7tImzNPLMNmE6HrDjobgeWPFev7Gvk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pb9pAIslNgMrTxuMHtYwKXZXxzO4TchevB-VVOOtcdw"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-iodine","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryIodine/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryIodine","unit":"mcg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryIodine, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryIodine/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryIodine","unit":"mcg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryIodine, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryIodine/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryIodine","unit":"mcg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryIodine, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryIron/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryIron","unit":"mg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-iron","display":"Dietary iron","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryIron"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vJ8yetTogGLlwqtxJzs6xnSXNYMOzvtXVDRMSEPZY_Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2O0ZOP9Nva_U09VEdnfszZZc33CtshVX7FeZ-38-R2E"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-iron","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryIron/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryIron","unit":"mg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-iron","display":"Dietary iron","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryIron"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vJ8yetTogGLlwqtxJzs6xnSXNYMOzvtXVDRMSEPZY_Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2O0ZOP9Nva_U09VEdnfszZZc33CtshVX7FeZ-38-R2E"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-iron","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryIron/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryIron","unit":"mg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-iron","display":"Dietary iron","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryIron"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vJ8yetTogGLlwqtxJzs6xnSXNYMOzvtXVDRMSEPZY_Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2O0ZOP9Nva_U09VEdnfszZZc33CtshVX7FeZ-38-R2E"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-iron","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryIron/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryIron","unit":"mg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-iron","display":"Dietary iron","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryIron"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vJ8yetTogGLlwqtxJzs6xnSXNYMOzvtXVDRMSEPZY_Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2O0ZOP9Nva_U09VEdnfszZZc33CtshVX7FeZ-38-R2E"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-iron","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryIron/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryIron","unit":"mg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-iron","display":"Dietary iron","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryIron"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vJ8yetTogGLlwqtxJzs6xnSXNYMOzvtXVDRMSEPZY_Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2O0ZOP9Nva_U09VEdnfszZZc33CtshVX7FeZ-38-R2E"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-iron","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryIron/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryIron","unit":"mg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-iron","display":"Dietary iron","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryIron"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vJ8yetTogGLlwqtxJzs6xnSXNYMOzvtXVDRMSEPZY_Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2O0ZOP9Nva_U09VEdnfszZZc33CtshVX7FeZ-38-R2E"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-iron","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryIron/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryIron","unit":"mg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryIron, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryIron/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryIron","unit":"mg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryIron, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryIron/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryIron","unit":"mg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryIron, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryMagnesium/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryMagnesium","unit":"mg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-magnesium","display":"Dietary magnesium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryMagnesium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I5Jp2ccHnmk_X5KjFvmsrcrzDgG-OryO6l1efvF2y-Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YAJkQeP7a2u3eJcqKajNBkr5ZN1HRPZn1ovDxfQ_m7s"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-magnesium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryMagnesium/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryMagnesium","unit":"mg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-magnesium","display":"Dietary magnesium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryMagnesium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I5Jp2ccHnmk_X5KjFvmsrcrzDgG-OryO6l1efvF2y-Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YAJkQeP7a2u3eJcqKajNBkr5ZN1HRPZn1ovDxfQ_m7s"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-magnesium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryMagnesium/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryMagnesium","unit":"mg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-magnesium","display":"Dietary magnesium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryMagnesium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I5Jp2ccHnmk_X5KjFvmsrcrzDgG-OryO6l1efvF2y-Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YAJkQeP7a2u3eJcqKajNBkr5ZN1HRPZn1ovDxfQ_m7s"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-magnesium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryMagnesium/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryMagnesium","unit":"mg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-magnesium","display":"Dietary magnesium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryMagnesium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I5Jp2ccHnmk_X5KjFvmsrcrzDgG-OryO6l1efvF2y-Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YAJkQeP7a2u3eJcqKajNBkr5ZN1HRPZn1ovDxfQ_m7s"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-magnesium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryMagnesium/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryMagnesium","unit":"mg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-magnesium","display":"Dietary magnesium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryMagnesium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I5Jp2ccHnmk_X5KjFvmsrcrzDgG-OryO6l1efvF2y-Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YAJkQeP7a2u3eJcqKajNBkr5ZN1HRPZn1ovDxfQ_m7s"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-magnesium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryMagnesium/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryMagnesium","unit":"mg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-magnesium","display":"Dietary magnesium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryMagnesium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I5Jp2ccHnmk_X5KjFvmsrcrzDgG-OryO6l1efvF2y-Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YAJkQeP7a2u3eJcqKajNBkr5ZN1HRPZn1ovDxfQ_m7s"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-magnesium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryMagnesium/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryMagnesium","unit":"mg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryMagnesium, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryMagnesium/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryMagnesium","unit":"mg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryMagnesium, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryMagnesium/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryMagnesium","unit":"mg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryMagnesium, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryManganese/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryManganese","unit":"mg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-manganese","display":"Dietary manganese","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryManganese"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2L2sTUDAGj_iqBaLk4C4KQrIfXqkV6SHKclU03P1IXg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kNXfegnH_KDDXk2FM_WGKb4oILRNnc5q0LLW2qKE4K0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-manganese","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryManganese/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryManganese","unit":"mg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-manganese","display":"Dietary manganese","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryManganese"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2L2sTUDAGj_iqBaLk4C4KQrIfXqkV6SHKclU03P1IXg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kNXfegnH_KDDXk2FM_WGKb4oILRNnc5q0LLW2qKE4K0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-manganese","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryManganese/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryManganese","unit":"mg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-manganese","display":"Dietary manganese","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryManganese"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2L2sTUDAGj_iqBaLk4C4KQrIfXqkV6SHKclU03P1IXg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kNXfegnH_KDDXk2FM_WGKb4oILRNnc5q0LLW2qKE4K0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-manganese","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryManganese/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryManganese","unit":"mg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-manganese","display":"Dietary manganese","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryManganese"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2L2sTUDAGj_iqBaLk4C4KQrIfXqkV6SHKclU03P1IXg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kNXfegnH_KDDXk2FM_WGKb4oILRNnc5q0LLW2qKE4K0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-manganese","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryManganese/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryManganese","unit":"mg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-manganese","display":"Dietary manganese","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryManganese"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2L2sTUDAGj_iqBaLk4C4KQrIfXqkV6SHKclU03P1IXg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kNXfegnH_KDDXk2FM_WGKb4oILRNnc5q0LLW2qKE4K0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-manganese","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryManganese/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryManganese","unit":"mg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-manganese","display":"Dietary manganese","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryManganese"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2L2sTUDAGj_iqBaLk4C4KQrIfXqkV6SHKclU03P1IXg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kNXfegnH_KDDXk2FM_WGKb4oILRNnc5q0LLW2qKE4K0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-manganese","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryManganese/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryManganese","unit":"mg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryManganese, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryManganese/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryManganese","unit":"mg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryManganese, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryManganese/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryManganese","unit":"mg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryManganese, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryMolybdenum/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryMolybdenum","unit":"mcg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-molybdenum","display":"Dietary molybdenum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryMolybdenum"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gDNciSKgfieV5LDWtPew-V95qS3G2-o0C24yFCJrUXk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NAR10gdIUyyFOXU-RLQOyOvgTSz2wuBbebnDAy-K8Tk"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-molybdenum","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryMolybdenum/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryMolybdenum","unit":"mcg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-molybdenum","display":"Dietary molybdenum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryMolybdenum"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gDNciSKgfieV5LDWtPew-V95qS3G2-o0C24yFCJrUXk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NAR10gdIUyyFOXU-RLQOyOvgTSz2wuBbebnDAy-K8Tk"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-molybdenum","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryMolybdenum/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryMolybdenum","unit":"mcg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-molybdenum","display":"Dietary molybdenum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryMolybdenum"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gDNciSKgfieV5LDWtPew-V95qS3G2-o0C24yFCJrUXk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NAR10gdIUyyFOXU-RLQOyOvgTSz2wuBbebnDAy-K8Tk"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-molybdenum","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryMolybdenum/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryMolybdenum","unit":"mcg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-molybdenum","display":"Dietary molybdenum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryMolybdenum"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gDNciSKgfieV5LDWtPew-V95qS3G2-o0C24yFCJrUXk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NAR10gdIUyyFOXU-RLQOyOvgTSz2wuBbebnDAy-K8Tk"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-molybdenum","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryMolybdenum/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryMolybdenum","unit":"mcg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-molybdenum","display":"Dietary molybdenum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryMolybdenum"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gDNciSKgfieV5LDWtPew-V95qS3G2-o0C24yFCJrUXk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NAR10gdIUyyFOXU-RLQOyOvgTSz2wuBbebnDAy-K8Tk"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-molybdenum","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryMolybdenum/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryMolybdenum","unit":"mcg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-molybdenum","display":"Dietary molybdenum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryMolybdenum"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gDNciSKgfieV5LDWtPew-V95qS3G2-o0C24yFCJrUXk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NAR10gdIUyyFOXU-RLQOyOvgTSz2wuBbebnDAy-K8Tk"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-molybdenum","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryMolybdenum/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryMolybdenum","unit":"mcg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryMolybdenum, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryMolybdenum/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryMolybdenum","unit":"mcg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryMolybdenum, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryMolybdenum/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryMolybdenum","unit":"mcg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryMolybdenum, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryNiacin/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryNiacin","unit":"mg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-niacin","display":"Dietary niacin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryNiacin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BgjA7z4j7HQp5dxnqTRP6KmUAtN1ZM1n3osEV7nVn2U"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fVPjTqMI3nPsRtyYydEB3WhjIJbDMnisUh2ahHX2Yng"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-niacin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryNiacin/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryNiacin","unit":"mg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-niacin","display":"Dietary niacin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryNiacin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BgjA7z4j7HQp5dxnqTRP6KmUAtN1ZM1n3osEV7nVn2U"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fVPjTqMI3nPsRtyYydEB3WhjIJbDMnisUh2ahHX2Yng"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-niacin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryNiacin/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryNiacin","unit":"mg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-niacin","display":"Dietary niacin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryNiacin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BgjA7z4j7HQp5dxnqTRP6KmUAtN1ZM1n3osEV7nVn2U"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fVPjTqMI3nPsRtyYydEB3WhjIJbDMnisUh2ahHX2Yng"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-niacin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryNiacin/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryNiacin","unit":"mg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-niacin","display":"Dietary niacin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryNiacin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BgjA7z4j7HQp5dxnqTRP6KmUAtN1ZM1n3osEV7nVn2U"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fVPjTqMI3nPsRtyYydEB3WhjIJbDMnisUh2ahHX2Yng"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-niacin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryNiacin/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryNiacin","unit":"mg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-niacin","display":"Dietary niacin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryNiacin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BgjA7z4j7HQp5dxnqTRP6KmUAtN1ZM1n3osEV7nVn2U"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fVPjTqMI3nPsRtyYydEB3WhjIJbDMnisUh2ahHX2Yng"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-niacin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryNiacin/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryNiacin","unit":"mg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-niacin","display":"Dietary niacin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryNiacin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BgjA7z4j7HQp5dxnqTRP6KmUAtN1ZM1n3osEV7nVn2U"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fVPjTqMI3nPsRtyYydEB3WhjIJbDMnisUh2ahHX2Yng"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-niacin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryNiacin/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryNiacin","unit":"mg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryNiacin, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryNiacin/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryNiacin","unit":"mg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryNiacin, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryNiacin/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryNiacin","unit":"mg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryNiacin, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPantothenicAcid/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPantothenicAcid","unit":"mg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-pantothenic-acid","display":"Dietary pantothenic acid","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryPantothenicAcid"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Hq3qZvRicrt4vi-Ul_Zlh2x9F58PoJEHOYufglhu4yU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qLef_ipoXu_S6yv5EtomnWgqZOD2rxkUfBTRTbgINw8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-pantothenic-acid","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPantothenicAcid/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPantothenicAcid","unit":"mg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-pantothenic-acid","display":"Dietary pantothenic acid","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryPantothenicAcid"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Hq3qZvRicrt4vi-Ul_Zlh2x9F58PoJEHOYufglhu4yU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qLef_ipoXu_S6yv5EtomnWgqZOD2rxkUfBTRTbgINw8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-pantothenic-acid","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPantothenicAcid/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPantothenicAcid","unit":"mg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-pantothenic-acid","display":"Dietary pantothenic acid","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryPantothenicAcid"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Hq3qZvRicrt4vi-Ul_Zlh2x9F58PoJEHOYufglhu4yU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qLef_ipoXu_S6yv5EtomnWgqZOD2rxkUfBTRTbgINw8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-pantothenic-acid","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPantothenicAcid/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPantothenicAcid","unit":"mg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-pantothenic-acid","display":"Dietary pantothenic acid","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryPantothenicAcid"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Hq3qZvRicrt4vi-Ul_Zlh2x9F58PoJEHOYufglhu4yU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qLef_ipoXu_S6yv5EtomnWgqZOD2rxkUfBTRTbgINw8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-pantothenic-acid","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPantothenicAcid/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPantothenicAcid","unit":"mg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-pantothenic-acid","display":"Dietary pantothenic acid","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryPantothenicAcid"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Hq3qZvRicrt4vi-Ul_Zlh2x9F58PoJEHOYufglhu4yU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qLef_ipoXu_S6yv5EtomnWgqZOD2rxkUfBTRTbgINw8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-pantothenic-acid","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPantothenicAcid/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPantothenicAcid","unit":"mg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-pantothenic-acid","display":"Dietary pantothenic acid","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryPantothenicAcid"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Hq3qZvRicrt4vi-Ul_Zlh2x9F58PoJEHOYufglhu4yU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qLef_ipoXu_S6yv5EtomnWgqZOD2rxkUfBTRTbgINw8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-pantothenic-acid","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPantothenicAcid/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPantothenicAcid","unit":"mg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryPantothenicAcid, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPantothenicAcid/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPantothenicAcid","unit":"mg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryPantothenicAcid, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPantothenicAcid/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPantothenicAcid","unit":"mg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryPantothenicAcid, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPhosphorus/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPhosphorus","unit":"mg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-phosphorus","display":"Dietary phosphorus","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryPhosphorus"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pbj6qPxzcF0KbnFqn3nB42uWbx2f1zR1wBLbYqkToN0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AFucXtluox31TCMwck_MGVjLpy1_xVU-yz-8Iyf6HlQ"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-phosphorus","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPhosphorus/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPhosphorus","unit":"mg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-phosphorus","display":"Dietary phosphorus","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryPhosphorus"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pbj6qPxzcF0KbnFqn3nB42uWbx2f1zR1wBLbYqkToN0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AFucXtluox31TCMwck_MGVjLpy1_xVU-yz-8Iyf6HlQ"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-phosphorus","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPhosphorus/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPhosphorus","unit":"mg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-phosphorus","display":"Dietary phosphorus","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryPhosphorus"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pbj6qPxzcF0KbnFqn3nB42uWbx2f1zR1wBLbYqkToN0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AFucXtluox31TCMwck_MGVjLpy1_xVU-yz-8Iyf6HlQ"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-phosphorus","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPhosphorus/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPhosphorus","unit":"mg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-phosphorus","display":"Dietary phosphorus","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryPhosphorus"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pbj6qPxzcF0KbnFqn3nB42uWbx2f1zR1wBLbYqkToN0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AFucXtluox31TCMwck_MGVjLpy1_xVU-yz-8Iyf6HlQ"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-phosphorus","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPhosphorus/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPhosphorus","unit":"mg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-phosphorus","display":"Dietary phosphorus","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryPhosphorus"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pbj6qPxzcF0KbnFqn3nB42uWbx2f1zR1wBLbYqkToN0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AFucXtluox31TCMwck_MGVjLpy1_xVU-yz-8Iyf6HlQ"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-phosphorus","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPhosphorus/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPhosphorus","unit":"mg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-phosphorus","display":"Dietary phosphorus","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryPhosphorus"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pbj6qPxzcF0KbnFqn3nB42uWbx2f1zR1wBLbYqkToN0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AFucXtluox31TCMwck_MGVjLpy1_xVU-yz-8Iyf6HlQ"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-phosphorus","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPhosphorus/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPhosphorus","unit":"mg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryPhosphorus, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPhosphorus/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPhosphorus","unit":"mg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryPhosphorus, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPhosphorus/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPhosphorus","unit":"mg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryPhosphorus, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPotassium/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPotassium","unit":"mg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-potassium","display":"Dietary potassium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryPotassium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OmjGx_xQRPDyh1Vx5-OOx6JRvf28tcYCbxi4hzB5Xl0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I-9vO6JeKyqon_IxuBGvt_y1ZB2Ny5oX2wnhc6IX8Hg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-potassium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPotassium/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPotassium","unit":"mg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-potassium","display":"Dietary potassium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryPotassium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OmjGx_xQRPDyh1Vx5-OOx6JRvf28tcYCbxi4hzB5Xl0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I-9vO6JeKyqon_IxuBGvt_y1ZB2Ny5oX2wnhc6IX8Hg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-potassium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPotassium/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPotassium","unit":"mg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-potassium","display":"Dietary potassium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryPotassium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OmjGx_xQRPDyh1Vx5-OOx6JRvf28tcYCbxi4hzB5Xl0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I-9vO6JeKyqon_IxuBGvt_y1ZB2Ny5oX2wnhc6IX8Hg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-potassium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPotassium/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPotassium","unit":"mg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-potassium","display":"Dietary potassium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryPotassium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OmjGx_xQRPDyh1Vx5-OOx6JRvf28tcYCbxi4hzB5Xl0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I-9vO6JeKyqon_IxuBGvt_y1ZB2Ny5oX2wnhc6IX8Hg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-potassium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPotassium/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPotassium","unit":"mg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-potassium","display":"Dietary potassium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryPotassium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OmjGx_xQRPDyh1Vx5-OOx6JRvf28tcYCbxi4hzB5Xl0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I-9vO6JeKyqon_IxuBGvt_y1ZB2Ny5oX2wnhc6IX8Hg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-potassium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPotassium/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPotassium","unit":"mg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-potassium","display":"Dietary potassium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryPotassium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OmjGx_xQRPDyh1Vx5-OOx6JRvf28tcYCbxi4hzB5Xl0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I-9vO6JeKyqon_IxuBGvt_y1ZB2Ny5oX2wnhc6IX8Hg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-potassium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPotassium/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPotassium","unit":"mg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryPotassium, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPotassium/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPotassium","unit":"mg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryPotassium, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryPotassium/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryPotassium","unit":"mg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryPotassium, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryProtein/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryProtein","unit":"g","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9080-3","display":"Protein intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryProtein"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:6daXmlxn0Fy-nfrMY9jgRqoBUZci4mQtJmRSuLYiBWY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:p6reW80RhJeTwmziVSl4jmUmY5boyPG9wl8EEpWNEdc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-protein","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryProtein/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryProtein","unit":"g","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9080-3","display":"Protein intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryProtein"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:6daXmlxn0Fy-nfrMY9jgRqoBUZci4mQtJmRSuLYiBWY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:p6reW80RhJeTwmziVSl4jmUmY5boyPG9wl8EEpWNEdc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-protein","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryProtein/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryProtein","unit":"g","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9080-3","display":"Protein intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryProtein"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:6daXmlxn0Fy-nfrMY9jgRqoBUZci4mQtJmRSuLYiBWY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:p6reW80RhJeTwmziVSl4jmUmY5boyPG9wl8EEpWNEdc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-protein","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryProtein/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryProtein","unit":"g","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9080-3","display":"Protein intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryProtein"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:6daXmlxn0Fy-nfrMY9jgRqoBUZci4mQtJmRSuLYiBWY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:p6reW80RhJeTwmziVSl4jmUmY5boyPG9wl8EEpWNEdc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-protein","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryProtein/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryProtein","unit":"g","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9080-3","display":"Protein intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryProtein"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:6daXmlxn0Fy-nfrMY9jgRqoBUZci4mQtJmRSuLYiBWY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:p6reW80RhJeTwmziVSl4jmUmY5boyPG9wl8EEpWNEdc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-protein","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryProtein/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryProtein","unit":"g","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9080-3","display":"Protein intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryProtein"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:6daXmlxn0Fy-nfrMY9jgRqoBUZci4mQtJmRSuLYiBWY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:p6reW80RhJeTwmziVSl4jmUmY5boyPG9wl8EEpWNEdc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-protein","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryProtein/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryProtein","unit":"g","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryProtein, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryProtein/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryProtein","unit":"g","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryProtein, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryProtein/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryProtein","unit":"g","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryProtein, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryRiboflavin/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryRiboflavin","unit":"mg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-riboflavin","display":"Dietary riboflavin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryRiboflavin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5A3GptAEh6TsardcE0VhpZJmMxbx8pzNBAXYW4-r_cs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ucoSXnG7VMqpUZxzCvV6YlkdqieV-KmHkPVwnzbE0DU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-riboflavin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryRiboflavin/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryRiboflavin","unit":"mg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-riboflavin","display":"Dietary riboflavin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryRiboflavin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5A3GptAEh6TsardcE0VhpZJmMxbx8pzNBAXYW4-r_cs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ucoSXnG7VMqpUZxzCvV6YlkdqieV-KmHkPVwnzbE0DU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-riboflavin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryRiboflavin/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryRiboflavin","unit":"mg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-riboflavin","display":"Dietary riboflavin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryRiboflavin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5A3GptAEh6TsardcE0VhpZJmMxbx8pzNBAXYW4-r_cs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ucoSXnG7VMqpUZxzCvV6YlkdqieV-KmHkPVwnzbE0DU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-riboflavin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryRiboflavin/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryRiboflavin","unit":"mg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-riboflavin","display":"Dietary riboflavin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryRiboflavin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5A3GptAEh6TsardcE0VhpZJmMxbx8pzNBAXYW4-r_cs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ucoSXnG7VMqpUZxzCvV6YlkdqieV-KmHkPVwnzbE0DU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-riboflavin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryRiboflavin/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryRiboflavin","unit":"mg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-riboflavin","display":"Dietary riboflavin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryRiboflavin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5A3GptAEh6TsardcE0VhpZJmMxbx8pzNBAXYW4-r_cs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ucoSXnG7VMqpUZxzCvV6YlkdqieV-KmHkPVwnzbE0DU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-riboflavin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryRiboflavin/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryRiboflavin","unit":"mg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-riboflavin","display":"Dietary riboflavin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryRiboflavin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5A3GptAEh6TsardcE0VhpZJmMxbx8pzNBAXYW4-r_cs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ucoSXnG7VMqpUZxzCvV6YlkdqieV-KmHkPVwnzbE0DU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-riboflavin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryRiboflavin/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryRiboflavin","unit":"mg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryRiboflavin, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryRiboflavin/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryRiboflavin","unit":"mg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryRiboflavin, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryRiboflavin/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryRiboflavin","unit":"mg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryRiboflavin, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySelenium/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySelenium","unit":"mcg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-selenium","display":"Dietary selenium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietarySelenium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:IyjUQZaO0fxZTwcdt_8Ct8EBR-DTP4CSHb4ZsyGOPHY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:CIfnG0LYoWpER94ppDXaqOMjRxrYrVGLfE6-yxXDzdg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-selenium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySelenium/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySelenium","unit":"mcg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-selenium","display":"Dietary selenium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietarySelenium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:IyjUQZaO0fxZTwcdt_8Ct8EBR-DTP4CSHb4ZsyGOPHY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:CIfnG0LYoWpER94ppDXaqOMjRxrYrVGLfE6-yxXDzdg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-selenium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySelenium/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySelenium","unit":"mcg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-selenium","display":"Dietary selenium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietarySelenium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:IyjUQZaO0fxZTwcdt_8Ct8EBR-DTP4CSHb4ZsyGOPHY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:CIfnG0LYoWpER94ppDXaqOMjRxrYrVGLfE6-yxXDzdg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-selenium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySelenium/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySelenium","unit":"mcg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-selenium","display":"Dietary selenium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietarySelenium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:IyjUQZaO0fxZTwcdt_8Ct8EBR-DTP4CSHb4ZsyGOPHY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:CIfnG0LYoWpER94ppDXaqOMjRxrYrVGLfE6-yxXDzdg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-selenium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySelenium/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySelenium","unit":"mcg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-selenium","display":"Dietary selenium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietarySelenium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:IyjUQZaO0fxZTwcdt_8Ct8EBR-DTP4CSHb4ZsyGOPHY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:CIfnG0LYoWpER94ppDXaqOMjRxrYrVGLfE6-yxXDzdg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-selenium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySelenium/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySelenium","unit":"mcg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-selenium","display":"Dietary selenium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietarySelenium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:IyjUQZaO0fxZTwcdt_8Ct8EBR-DTP4CSHb4ZsyGOPHY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:CIfnG0LYoWpER94ppDXaqOMjRxrYrVGLfE6-yxXDzdg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-selenium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySelenium/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySelenium","unit":"mcg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietarySelenium, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySelenium/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySelenium","unit":"mcg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietarySelenium, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySelenium/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySelenium","unit":"mcg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietarySelenium, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySodium/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySodium","unit":"mg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-sodium","display":"Dietary sodium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietarySodium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:w0nmSfl-3INFvmj5rkOjiL1rCD7VxAOUAH0u_TREhAw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:79R7JAzcMSqbWpe76mLYsiAmwG-vh6VoZTBsYN3Zkps"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-sodium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySodium/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySodium","unit":"mg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-sodium","display":"Dietary sodium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietarySodium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:w0nmSfl-3INFvmj5rkOjiL1rCD7VxAOUAH0u_TREhAw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:79R7JAzcMSqbWpe76mLYsiAmwG-vh6VoZTBsYN3Zkps"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-sodium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySodium/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySodium","unit":"mg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-sodium","display":"Dietary sodium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietarySodium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:w0nmSfl-3INFvmj5rkOjiL1rCD7VxAOUAH0u_TREhAw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:79R7JAzcMSqbWpe76mLYsiAmwG-vh6VoZTBsYN3Zkps"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-sodium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySodium/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySodium","unit":"mg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-sodium","display":"Dietary sodium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietarySodium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:w0nmSfl-3INFvmj5rkOjiL1rCD7VxAOUAH0u_TREhAw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:79R7JAzcMSqbWpe76mLYsiAmwG-vh6VoZTBsYN3Zkps"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-sodium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySodium/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySodium","unit":"mg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-sodium","display":"Dietary sodium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietarySodium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:w0nmSfl-3INFvmj5rkOjiL1rCD7VxAOUAH0u_TREhAw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:79R7JAzcMSqbWpe76mLYsiAmwG-vh6VoZTBsYN3Zkps"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-sodium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySodium/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySodium","unit":"mg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-sodium","display":"Dietary sodium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietarySodium"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:w0nmSfl-3INFvmj5rkOjiL1rCD7VxAOUAH0u_TREhAw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:79R7JAzcMSqbWpe76mLYsiAmwG-vh6VoZTBsYN3Zkps"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-sodium","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySodium/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySodium","unit":"mg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietarySodium, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySodium/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySodium","unit":"mg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietarySodium, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySodium/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySodium","unit":"mg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietarySodium, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySugar/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySugar","unit":"g","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-sugar","display":"Dietary sugar","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietarySugar"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5r_ufTEhYjXx_hAT92twhxTfLLTRf1KIQxr_KBtQPpg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:UnjPFWM4gmy3adNIUUFXJkp6Se8G3v_TbZGlniAEG04"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-sugar","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySugar/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySugar","unit":"g","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-sugar","display":"Dietary sugar","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietarySugar"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5r_ufTEhYjXx_hAT92twhxTfLLTRf1KIQxr_KBtQPpg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:UnjPFWM4gmy3adNIUUFXJkp6Se8G3v_TbZGlniAEG04"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-sugar","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySugar/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySugar","unit":"g","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-sugar","display":"Dietary sugar","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietarySugar"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5r_ufTEhYjXx_hAT92twhxTfLLTRf1KIQxr_KBtQPpg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:UnjPFWM4gmy3adNIUUFXJkp6Se8G3v_TbZGlniAEG04"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-sugar","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySugar/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySugar","unit":"g","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-sugar","display":"Dietary sugar","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietarySugar"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5r_ufTEhYjXx_hAT92twhxTfLLTRf1KIQxr_KBtQPpg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:UnjPFWM4gmy3adNIUUFXJkp6Se8G3v_TbZGlniAEG04"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-sugar","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySugar/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySugar","unit":"g","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-sugar","display":"Dietary sugar","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietarySugar"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5r_ufTEhYjXx_hAT92twhxTfLLTRf1KIQxr_KBtQPpg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:UnjPFWM4gmy3adNIUUFXJkp6Se8G3v_TbZGlniAEG04"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-sugar","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySugar/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySugar","unit":"g","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-sugar","display":"Dietary sugar","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietarySugar"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5r_ufTEhYjXx_hAT92twhxTfLLTRf1KIQxr_KBtQPpg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:UnjPFWM4gmy3adNIUUFXJkp6Se8G3v_TbZGlniAEG04"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-sugar","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"g","system":"http://unitsofmeasure.org","unit":"g","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySugar/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySugar","unit":"g","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietarySugar, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySugar/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySugar","unit":"g","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietarySugar, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietarySugar/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietarySugar","unit":"g","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietarySugar, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryThiamin/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryThiamin","unit":"mg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-thiamin","display":"Dietary thiamin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryThiamin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:h_WdrPihtcJwj2xUZuUbuM9UvjfjMgt2o3CVQqLp4a4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qSUnEf2NjHpizQdqSteVERsmLCyf09w-n1sZuAgiaFo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-thiamin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryThiamin/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryThiamin","unit":"mg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-thiamin","display":"Dietary thiamin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryThiamin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:h_WdrPihtcJwj2xUZuUbuM9UvjfjMgt2o3CVQqLp4a4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qSUnEf2NjHpizQdqSteVERsmLCyf09w-n1sZuAgiaFo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-thiamin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryThiamin/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryThiamin","unit":"mg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-thiamin","display":"Dietary thiamin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryThiamin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:h_WdrPihtcJwj2xUZuUbuM9UvjfjMgt2o3CVQqLp4a4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qSUnEf2NjHpizQdqSteVERsmLCyf09w-n1sZuAgiaFo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-thiamin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryThiamin/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryThiamin","unit":"mg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-thiamin","display":"Dietary thiamin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryThiamin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:h_WdrPihtcJwj2xUZuUbuM9UvjfjMgt2o3CVQqLp4a4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qSUnEf2NjHpizQdqSteVERsmLCyf09w-n1sZuAgiaFo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-thiamin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryThiamin/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryThiamin","unit":"mg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-thiamin","display":"Dietary thiamin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryThiamin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:h_WdrPihtcJwj2xUZuUbuM9UvjfjMgt2o3CVQqLp4a4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qSUnEf2NjHpizQdqSteVERsmLCyf09w-n1sZuAgiaFo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-thiamin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryThiamin/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryThiamin","unit":"mg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-thiamin","display":"Dietary thiamin","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryThiamin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:h_WdrPihtcJwj2xUZuUbuM9UvjfjMgt2o3CVQqLp4a4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qSUnEf2NjHpizQdqSteVERsmLCyf09w-n1sZuAgiaFo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-thiamin","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryThiamin/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryThiamin","unit":"mg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryThiamin, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryThiamin/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryThiamin","unit":"mg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryThiamin, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryThiamin/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryThiamin","unit":"mg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryThiamin, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminA/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminA","unit":"mcg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-a","display":"Dietary vitamin A","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminA"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:M2FEp5BeDLucMKZaoz1hle2N7JbVOPzL-6MneQbh8RM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:GXgzmitdjdNX5_jvUiGZHXevm5kXa1NsetdZUSIMvn0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-a","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminA/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminA","unit":"mcg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-a","display":"Dietary vitamin A","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminA"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:M2FEp5BeDLucMKZaoz1hle2N7JbVOPzL-6MneQbh8RM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:GXgzmitdjdNX5_jvUiGZHXevm5kXa1NsetdZUSIMvn0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-a","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminA/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminA","unit":"mcg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-a","display":"Dietary vitamin A","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminA"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:M2FEp5BeDLucMKZaoz1hle2N7JbVOPzL-6MneQbh8RM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:GXgzmitdjdNX5_jvUiGZHXevm5kXa1NsetdZUSIMvn0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-a","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminA/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminA","unit":"mcg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-a","display":"Dietary vitamin A","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminA"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:M2FEp5BeDLucMKZaoz1hle2N7JbVOPzL-6MneQbh8RM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:GXgzmitdjdNX5_jvUiGZHXevm5kXa1NsetdZUSIMvn0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-a","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminA/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminA","unit":"mcg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-a","display":"Dietary vitamin A","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminA"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:M2FEp5BeDLucMKZaoz1hle2N7JbVOPzL-6MneQbh8RM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:GXgzmitdjdNX5_jvUiGZHXevm5kXa1NsetdZUSIMvn0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-a","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminA/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminA","unit":"mcg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-a","display":"Dietary vitamin A","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminA"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:M2FEp5BeDLucMKZaoz1hle2N7JbVOPzL-6MneQbh8RM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:GXgzmitdjdNX5_jvUiGZHXevm5kXa1NsetdZUSIMvn0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-a","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminA/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminA","unit":"mcg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryVitaminA, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminA/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminA","unit":"mcg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryVitaminA, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminA/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminA","unit":"mcg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryVitaminA, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminB12/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminB12","unit":"mcg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-b12","display":"Dietary vitamin B12","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminB12"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:bpSGJFlWtdxBiozRd4MsedP7xeerTSbZ0TnLzFS4Zgc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gHkJPX7OM2Z0JuW04W2BHGVP1ko2s2knVjLaYDz0FSc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-b12","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminB12/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminB12","unit":"mcg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-b12","display":"Dietary vitamin B12","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminB12"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:bpSGJFlWtdxBiozRd4MsedP7xeerTSbZ0TnLzFS4Zgc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gHkJPX7OM2Z0JuW04W2BHGVP1ko2s2knVjLaYDz0FSc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-b12","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminB12/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminB12","unit":"mcg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-b12","display":"Dietary vitamin B12","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminB12"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:bpSGJFlWtdxBiozRd4MsedP7xeerTSbZ0TnLzFS4Zgc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gHkJPX7OM2Z0JuW04W2BHGVP1ko2s2knVjLaYDz0FSc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-b12","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminB12/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminB12","unit":"mcg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-b12","display":"Dietary vitamin B12","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminB12"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:bpSGJFlWtdxBiozRd4MsedP7xeerTSbZ0TnLzFS4Zgc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gHkJPX7OM2Z0JuW04W2BHGVP1ko2s2knVjLaYDz0FSc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-b12","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminB12/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminB12","unit":"mcg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-b12","display":"Dietary vitamin B12","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminB12"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:bpSGJFlWtdxBiozRd4MsedP7xeerTSbZ0TnLzFS4Zgc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gHkJPX7OM2Z0JuW04W2BHGVP1ko2s2knVjLaYDz0FSc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-b12","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminB12/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminB12","unit":"mcg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-b12","display":"Dietary vitamin B12","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminB12"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:bpSGJFlWtdxBiozRd4MsedP7xeerTSbZ0TnLzFS4Zgc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gHkJPX7OM2Z0JuW04W2BHGVP1ko2s2knVjLaYDz0FSc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-b12","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminB12/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminB12","unit":"mcg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryVitaminB12, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminB12/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminB12","unit":"mcg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryVitaminB12, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminB12/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminB12","unit":"mcg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryVitaminB12, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminB6/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminB6","unit":"mg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-b6","display":"Dietary vitamin B6","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminB6"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:cQRREvTpe1PD3yI63NPCJn7OsDV4kpzKXih3EpNbKuQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-f30hwbizx_mB5FSjPXhdlFYpiXiYtr7FnXxBCtKnVY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-b6","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminB6/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminB6","unit":"mg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-b6","display":"Dietary vitamin B6","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminB6"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:cQRREvTpe1PD3yI63NPCJn7OsDV4kpzKXih3EpNbKuQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-f30hwbizx_mB5FSjPXhdlFYpiXiYtr7FnXxBCtKnVY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-b6","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminB6/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminB6","unit":"mg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-b6","display":"Dietary vitamin B6","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminB6"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:cQRREvTpe1PD3yI63NPCJn7OsDV4kpzKXih3EpNbKuQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-f30hwbizx_mB5FSjPXhdlFYpiXiYtr7FnXxBCtKnVY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-b6","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminB6/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminB6","unit":"mg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-b6","display":"Dietary vitamin B6","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminB6"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:cQRREvTpe1PD3yI63NPCJn7OsDV4kpzKXih3EpNbKuQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-f30hwbizx_mB5FSjPXhdlFYpiXiYtr7FnXxBCtKnVY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-b6","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminB6/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminB6","unit":"mg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-b6","display":"Dietary vitamin B6","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminB6"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:cQRREvTpe1PD3yI63NPCJn7OsDV4kpzKXih3EpNbKuQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-f30hwbizx_mB5FSjPXhdlFYpiXiYtr7FnXxBCtKnVY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-b6","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminB6/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminB6","unit":"mg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-b6","display":"Dietary vitamin B6","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminB6"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:cQRREvTpe1PD3yI63NPCJn7OsDV4kpzKXih3EpNbKuQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-f30hwbizx_mB5FSjPXhdlFYpiXiYtr7FnXxBCtKnVY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-b6","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminB6/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminB6","unit":"mg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryVitaminB6, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminB6/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminB6","unit":"mg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryVitaminB6, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminB6/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminB6","unit":"mg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryVitaminB6, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminC/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminC","unit":"mg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-c","display":"Dietary vitamin C","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminC"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5nDthOMcmg7ubn916eWXK5V0RijWuGKwMGa4GkRAvaA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:10BI9cenWmCHyRjh72kHdP839BdynOFEA4Udz0ieM6E"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-c","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminC/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminC","unit":"mg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-c","display":"Dietary vitamin C","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminC"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5nDthOMcmg7ubn916eWXK5V0RijWuGKwMGa4GkRAvaA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:10BI9cenWmCHyRjh72kHdP839BdynOFEA4Udz0ieM6E"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-c","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminC/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminC","unit":"mg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-c","display":"Dietary vitamin C","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminC"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5nDthOMcmg7ubn916eWXK5V0RijWuGKwMGa4GkRAvaA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:10BI9cenWmCHyRjh72kHdP839BdynOFEA4Udz0ieM6E"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-c","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminC/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminC","unit":"mg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-c","display":"Dietary vitamin C","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminC"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5nDthOMcmg7ubn916eWXK5V0RijWuGKwMGa4GkRAvaA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:10BI9cenWmCHyRjh72kHdP839BdynOFEA4Udz0ieM6E"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-c","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminC/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminC","unit":"mg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-c","display":"Dietary vitamin C","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminC"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5nDthOMcmg7ubn916eWXK5V0RijWuGKwMGa4GkRAvaA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:10BI9cenWmCHyRjh72kHdP839BdynOFEA4Udz0ieM6E"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-c","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminC/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminC","unit":"mg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-c","display":"Dietary vitamin C","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminC"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5nDthOMcmg7ubn916eWXK5V0RijWuGKwMGa4GkRAvaA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:10BI9cenWmCHyRjh72kHdP839BdynOFEA4Udz0ieM6E"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-c","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminC/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminC","unit":"mg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryVitaminC, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminC/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminC","unit":"mg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryVitaminC, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminC/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminC","unit":"mg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryVitaminC, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminD/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminD","unit":"mcg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-d","display":"Dietary vitamin D","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminD"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_PepPRyNvQYmk9lfZV6hRTZ8zR0_PQAptST_XbskF2U"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:SiRDQ9LBYxeUrgGk5k8b_f13o4xbhf78ZV5l5s3vAuA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-d","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminD/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminD","unit":"mcg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-d","display":"Dietary vitamin D","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminD"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_PepPRyNvQYmk9lfZV6hRTZ8zR0_PQAptST_XbskF2U"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:SiRDQ9LBYxeUrgGk5k8b_f13o4xbhf78ZV5l5s3vAuA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-d","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminD/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminD","unit":"mcg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-d","display":"Dietary vitamin D","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminD"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_PepPRyNvQYmk9lfZV6hRTZ8zR0_PQAptST_XbskF2U"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:SiRDQ9LBYxeUrgGk5k8b_f13o4xbhf78ZV5l5s3vAuA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-d","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminD/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminD","unit":"mcg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-d","display":"Dietary vitamin D","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminD"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_PepPRyNvQYmk9lfZV6hRTZ8zR0_PQAptST_XbskF2U"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:SiRDQ9LBYxeUrgGk5k8b_f13o4xbhf78ZV5l5s3vAuA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-d","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminD/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminD","unit":"mcg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-d","display":"Dietary vitamin D","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminD"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_PepPRyNvQYmk9lfZV6hRTZ8zR0_PQAptST_XbskF2U"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:SiRDQ9LBYxeUrgGk5k8b_f13o4xbhf78ZV5l5s3vAuA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-d","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminD/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminD","unit":"mcg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-d","display":"Dietary vitamin D","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminD"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_PepPRyNvQYmk9lfZV6hRTZ8zR0_PQAptST_XbskF2U"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:SiRDQ9LBYxeUrgGk5k8b_f13o4xbhf78ZV5l5s3vAuA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-d","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminD/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminD","unit":"mcg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryVitaminD, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminD/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminD","unit":"mcg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryVitaminD, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminD/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminD","unit":"mcg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryVitaminD, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminE/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminE","unit":"mg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-e","display":"Dietary vitamin E","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminE"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BljaJIuLRQu1DHY8FWgXOjaoofid-PToXIwYTy9VTz8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:b0XUGZLkKPt3MycOKa2grnkMdGvH8YjLmSh4lN85cLw"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-e","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminE/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminE","unit":"mg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-e","display":"Dietary vitamin E","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminE"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BljaJIuLRQu1DHY8FWgXOjaoofid-PToXIwYTy9VTz8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:b0XUGZLkKPt3MycOKa2grnkMdGvH8YjLmSh4lN85cLw"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-e","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminE/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminE","unit":"mg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-e","display":"Dietary vitamin E","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminE"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BljaJIuLRQu1DHY8FWgXOjaoofid-PToXIwYTy9VTz8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:b0XUGZLkKPt3MycOKa2grnkMdGvH8YjLmSh4lN85cLw"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-e","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminE/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminE","unit":"mg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-e","display":"Dietary vitamin E","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminE"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BljaJIuLRQu1DHY8FWgXOjaoofid-PToXIwYTy9VTz8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:b0XUGZLkKPt3MycOKa2grnkMdGvH8YjLmSh4lN85cLw"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-e","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminE/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminE","unit":"mg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-e","display":"Dietary vitamin E","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminE"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BljaJIuLRQu1DHY8FWgXOjaoofid-PToXIwYTy9VTz8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:b0XUGZLkKPt3MycOKa2grnkMdGvH8YjLmSh4lN85cLw"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-e","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminE/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminE","unit":"mg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-e","display":"Dietary vitamin E","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminE"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BljaJIuLRQu1DHY8FWgXOjaoofid-PToXIwYTy9VTz8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:b0XUGZLkKPt3MycOKa2grnkMdGvH8YjLmSh4lN85cLw"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-e","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminE/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminE","unit":"mg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryVitaminE, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminE/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminE","unit":"mg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryVitaminE, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminE/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminE","unit":"mg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryVitaminE, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminK/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminK","unit":"mcg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-k","display":"Dietary vitamin K","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminK"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ks9259Z3APhD1ZdAS0PxIBaHgjfrj-GIFr0jMc9MEIQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-6TNvZD6lWyjYuQ2Z_iDL2jTavhsww8fMK7k-6F2LLM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-k","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminK/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminK","unit":"mcg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-k","display":"Dietary vitamin K","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminK"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ks9259Z3APhD1ZdAS0PxIBaHgjfrj-GIFr0jMc9MEIQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-6TNvZD6lWyjYuQ2Z_iDL2jTavhsww8fMK7k-6F2LLM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-k","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminK/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminK","unit":"mcg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-k","display":"Dietary vitamin K","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminK"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ks9259Z3APhD1ZdAS0PxIBaHgjfrj-GIFr0jMc9MEIQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-6TNvZD6lWyjYuQ2Z_iDL2jTavhsww8fMK7k-6F2LLM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-k","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminK/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminK","unit":"mcg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-k","display":"Dietary vitamin K","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminK"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ks9259Z3APhD1ZdAS0PxIBaHgjfrj-GIFr0jMc9MEIQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-6TNvZD6lWyjYuQ2Z_iDL2jTavhsww8fMK7k-6F2LLM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-k","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminK/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminK","unit":"mcg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-k","display":"Dietary vitamin K","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminK"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ks9259Z3APhD1ZdAS0PxIBaHgjfrj-GIFr0jMc9MEIQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-6TNvZD6lWyjYuQ2Z_iDL2jTavhsww8fMK7k-6F2LLM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-k","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminK/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminK","unit":"mcg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-vitamin-k","display":"Dietary vitamin K","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryVitaminK"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ks9259Z3APhD1ZdAS0PxIBaHgjfrj-GIFr0jMc9MEIQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-6TNvZD6lWyjYuQ2Z_iDL2jTavhsww8fMK7k-6F2LLM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-k","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ug","system":"http://unitsofmeasure.org","unit":"ug","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminK/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminK","unit":"mcg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryVitaminK, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminK/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminK","unit":"mcg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryVitaminK, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryVitaminK/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryVitaminK","unit":"mcg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryVitaminK, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryWater/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryWater","unit":"mL","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"8985-4","display":"Fluid intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryWater"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:LjHLWRzWmF040F325tbKmVuHpn4w9sOd8sLruSC-0Ws"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1JDUneSpMaw1KoL-z4N6709o5WkH_7NQyLjB0hjMI6E"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-fluid-intake","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mL","system":"http://unitsofmeasure.org","unit":"mL","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryWater/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryWater","unit":"mL","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"8985-4","display":"Fluid intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryWater"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:LjHLWRzWmF040F325tbKmVuHpn4w9sOd8sLruSC-0Ws"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1JDUneSpMaw1KoL-z4N6709o5WkH_7NQyLjB0hjMI6E"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-fluid-intake","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mL","system":"http://unitsofmeasure.org","unit":"mL","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryWater/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryWater","unit":"mL","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"8985-4","display":"Fluid intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryWater"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:LjHLWRzWmF040F325tbKmVuHpn4w9sOd8sLruSC-0Ws"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1JDUneSpMaw1KoL-z4N6709o5WkH_7NQyLjB0hjMI6E"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-fluid-intake","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mL","system":"http://unitsofmeasure.org","unit":"mL","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryWater/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryWater","unit":"mL","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"8985-4","display":"Fluid intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryWater"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:LjHLWRzWmF040F325tbKmVuHpn4w9sOd8sLruSC-0Ws"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1JDUneSpMaw1KoL-z4N6709o5WkH_7NQyLjB0hjMI6E"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-fluid-intake","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mL","system":"http://unitsofmeasure.org","unit":"mL","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryWater/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryWater","unit":"mL","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"8985-4","display":"Fluid intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryWater"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:LjHLWRzWmF040F325tbKmVuHpn4w9sOd8sLruSC-0Ws"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1JDUneSpMaw1KoL-z4N6709o5WkH_7NQyLjB0hjMI6E"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-fluid-intake","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mL","system":"http://unitsofmeasure.org","unit":"mL","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryWater/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryWater","unit":"mL","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"8985-4","display":"Fluid intake Measured","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryWater"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:LjHLWRzWmF040F325tbKmVuHpn4w9sOd8sLruSC-0Ws"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1JDUneSpMaw1KoL-z4N6709o5WkH_7NQyLjB0hjMI6E"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-fluid-intake","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mL","system":"http://unitsofmeasure.org","unit":"mL","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryWater/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryWater","unit":"mL","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryWater, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryWater/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryWater","unit":"mL","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryWater, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryWater/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryWater","unit":"mL","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryWater, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryZinc/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryZinc","unit":"mg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-zinc","display":"Dietary zinc","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryZinc"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gGUAljlKJQqoXFJ1_dIWAYgP5qLdqSXZqwVgcTlb9Bg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-2IH-vkXQ9hoqGRTrLhvJ18mpGcIjaT7VdiGUPbq0Rs"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-zinc","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryZinc/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryZinc","unit":"mg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-zinc","display":"Dietary zinc","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryZinc"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gGUAljlKJQqoXFJ1_dIWAYgP5qLdqSXZqwVgcTlb9Bg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-2IH-vkXQ9hoqGRTrLhvJ18mpGcIjaT7VdiGUPbq0Rs"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-zinc","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryZinc/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryZinc","unit":"mg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-zinc","display":"Dietary zinc","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryZinc"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gGUAljlKJQqoXFJ1_dIWAYgP5qLdqSXZqwVgcTlb9Bg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-2IH-vkXQ9hoqGRTrLhvJ18mpGcIjaT7VdiGUPbq0Rs"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-zinc","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryZinc/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryZinc","unit":"mg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-zinc","display":"Dietary zinc","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryZinc"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gGUAljlKJQqoXFJ1_dIWAYgP5qLdqSXZqwVgcTlb9Bg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-2IH-vkXQ9hoqGRTrLhvJ18mpGcIjaT7VdiGUPbq0Rs"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-zinc","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryZinc/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryZinc","unit":"mg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-zinc","display":"Dietary zinc","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryZinc"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gGUAljlKJQqoXFJ1_dIWAYgP5qLdqSXZqwVgcTlb9Bg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-2IH-vkXQ9hoqGRTrLhvJ18mpGcIjaT7VdiGUPbq0Rs"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-zinc","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryZinc/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryZinc","unit":"mg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"dietary-zinc","display":"Dietary zinc","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryZinc"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gGUAljlKJQqoXFJ1_dIWAYgP5qLdqSXZqwVgcTlb9Bg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-2IH-vkXQ9hoqGRTrLhvJ18mpGcIjaT7VdiGUPbq0Rs"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-zinc","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mg","system":"http://unitsofmeasure.org","unit":"mg","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryZinc/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryZinc","unit":"mg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryZinc, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryZinc/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryZinc","unit":"mg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryZinc, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDietaryZinc/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryZinc","unit":"mg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryZinc, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceCrossCountrySkiing/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zmkxSNehbVAN5U9s2IBlYf3IYGv4PZasS3SOpQ0-sJo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:a4JGmZ478fRLECy7SUwd1QYDPpgnrpPrifwF4cKOHwE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceCrossCountrySkiing/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zmkxSNehbVAN5U9s2IBlYf3IYGv4PZasS3SOpQ0-sJo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:a4JGmZ478fRLECy7SUwd1QYDPpgnrpPrifwF4cKOHwE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceCrossCountrySkiing/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zmkxSNehbVAN5U9s2IBlYf3IYGv4PZasS3SOpQ0-sJo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:a4JGmZ478fRLECy7SUwd1QYDPpgnrpPrifwF4cKOHwE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceCrossCountrySkiing/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zmkxSNehbVAN5U9s2IBlYf3IYGv4PZasS3SOpQ0-sJo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:a4JGmZ478fRLECy7SUwd1QYDPpgnrpPrifwF4cKOHwE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceCrossCountrySkiing/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zmkxSNehbVAN5U9s2IBlYf3IYGv4PZasS3SOpQ0-sJo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:a4JGmZ478fRLECy7SUwd1QYDPpgnrpPrifwF4cKOHwE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceCrossCountrySkiing/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zmkxSNehbVAN5U9s2IBlYf3IYGv4PZasS3SOpQ0-sJo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:a4JGmZ478fRLECy7SUwd1QYDPpgnrpPrifwF4cKOHwE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceCrossCountrySkiing/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceCrossCountrySkiing, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceCrossCountrySkiing/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceCrossCountrySkiing, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceCrossCountrySkiing/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceCrossCountrySkiing, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceCycling/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceCycling"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:DAbshnwfILtKwEUCEDBZxQhz-GH9snyW_dd36FzsPUs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:icoAzYzCP4C240TZetIazH1sFqq426YnNNpk4UHULxQ"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceCycling/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceCycling"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:DAbshnwfILtKwEUCEDBZxQhz-GH9snyW_dd36FzsPUs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:icoAzYzCP4C240TZetIazH1sFqq426YnNNpk4UHULxQ"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceCycling/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceCycling"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:DAbshnwfILtKwEUCEDBZxQhz-GH9snyW_dd36FzsPUs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:icoAzYzCP4C240TZetIazH1sFqq426YnNNpk4UHULxQ"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceCycling/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceCycling"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:DAbshnwfILtKwEUCEDBZxQhz-GH9snyW_dd36FzsPUs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:icoAzYzCP4C240TZetIazH1sFqq426YnNNpk4UHULxQ"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceCycling/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceCycling"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:DAbshnwfILtKwEUCEDBZxQhz-GH9snyW_dd36FzsPUs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:icoAzYzCP4C240TZetIazH1sFqq426YnNNpk4UHULxQ"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceCycling/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceCycling"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:DAbshnwfILtKwEUCEDBZxQhz-GH9snyW_dd36FzsPUs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:icoAzYzCP4C240TZetIazH1sFqq426YnNNpk4UHULxQ"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceCycling/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceCycling, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceCycling/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceCycling, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceCycling/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceCycling, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceDownhillSnowSports/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceDownhillSnowSports"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dByZ5ECdHIDlud0Ii9Ex_eCgUz2RomgJH2v1w2pkIzQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1QrH98Fger7u4NZnZks_tXCrOiDrRQIOEo9K0SCNykU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceDownhillSnowSports/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceDownhillSnowSports"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dByZ5ECdHIDlud0Ii9Ex_eCgUz2RomgJH2v1w2pkIzQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1QrH98Fger7u4NZnZks_tXCrOiDrRQIOEo9K0SCNykU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceDownhillSnowSports/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceDownhillSnowSports"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dByZ5ECdHIDlud0Ii9Ex_eCgUz2RomgJH2v1w2pkIzQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1QrH98Fger7u4NZnZks_tXCrOiDrRQIOEo9K0SCNykU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceDownhillSnowSports/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceDownhillSnowSports"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dByZ5ECdHIDlud0Ii9Ex_eCgUz2RomgJH2v1w2pkIzQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1QrH98Fger7u4NZnZks_tXCrOiDrRQIOEo9K0SCNykU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceDownhillSnowSports/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceDownhillSnowSports"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dByZ5ECdHIDlud0Ii9Ex_eCgUz2RomgJH2v1w2pkIzQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1QrH98Fger7u4NZnZks_tXCrOiDrRQIOEo9K0SCNykU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceDownhillSnowSports/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceDownhillSnowSports"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dByZ5ECdHIDlud0Ii9Ex_eCgUz2RomgJH2v1w2pkIzQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1QrH98Fger7u4NZnZks_tXCrOiDrRQIOEo9K0SCNykU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceDownhillSnowSports/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceDownhillSnowSports, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceDownhillSnowSports/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceDownhillSnowSports, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceDownhillSnowSports/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceDownhillSnowSports, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistancePaddleSports/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistancePaddleSports"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Z0utqmrCsA6f-ebDIl1XI1tttzhzicb_Mzcq0W0So3E"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1ThihyfRtWsYDCkWfM2KqsFVM2CmDmwOcyf44S__gDU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistancePaddleSports/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistancePaddleSports"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Z0utqmrCsA6f-ebDIl1XI1tttzhzicb_Mzcq0W0So3E"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1ThihyfRtWsYDCkWfM2KqsFVM2CmDmwOcyf44S__gDU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistancePaddleSports/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistancePaddleSports"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Z0utqmrCsA6f-ebDIl1XI1tttzhzicb_Mzcq0W0So3E"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1ThihyfRtWsYDCkWfM2KqsFVM2CmDmwOcyf44S__gDU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistancePaddleSports/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistancePaddleSports"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Z0utqmrCsA6f-ebDIl1XI1tttzhzicb_Mzcq0W0So3E"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1ThihyfRtWsYDCkWfM2KqsFVM2CmDmwOcyf44S__gDU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistancePaddleSports/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistancePaddleSports"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Z0utqmrCsA6f-ebDIl1XI1tttzhzicb_Mzcq0W0So3E"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1ThihyfRtWsYDCkWfM2KqsFVM2CmDmwOcyf44S__gDU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistancePaddleSports/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistancePaddleSports"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Z0utqmrCsA6f-ebDIl1XI1tttzhzicb_Mzcq0W0So3E"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1ThihyfRtWsYDCkWfM2KqsFVM2CmDmwOcyf44S__gDU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistancePaddleSports/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distancePaddleSports, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistancePaddleSports/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distancePaddleSports, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistancePaddleSports/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distancePaddleSports, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceRowing/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceRowing"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:SYPevrHVHxTxMmHYcioq1kUPW4XhVBcF5mqmuhcDJhQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-6iO_5zIIaBBdS0lsnI7weVe7bnVxq0eMi3IxbJ5Vd4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceRowing/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceRowing"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:SYPevrHVHxTxMmHYcioq1kUPW4XhVBcF5mqmuhcDJhQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-6iO_5zIIaBBdS0lsnI7weVe7bnVxq0eMi3IxbJ5Vd4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceRowing/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceRowing"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:SYPevrHVHxTxMmHYcioq1kUPW4XhVBcF5mqmuhcDJhQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-6iO_5zIIaBBdS0lsnI7weVe7bnVxq0eMi3IxbJ5Vd4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceRowing/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceRowing"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:SYPevrHVHxTxMmHYcioq1kUPW4XhVBcF5mqmuhcDJhQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-6iO_5zIIaBBdS0lsnI7weVe7bnVxq0eMi3IxbJ5Vd4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceRowing/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceRowing"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:SYPevrHVHxTxMmHYcioq1kUPW4XhVBcF5mqmuhcDJhQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-6iO_5zIIaBBdS0lsnI7weVe7bnVxq0eMi3IxbJ5Vd4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceRowing/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceRowing"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:SYPevrHVHxTxMmHYcioq1kUPW4XhVBcF5mqmuhcDJhQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-6iO_5zIIaBBdS0lsnI7weVe7bnVxq0eMi3IxbJ5Vd4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceRowing/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceRowing, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceRowing/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceRowing, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceRowing/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceRowing, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceSkatingSports/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceSkatingSports"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I-aciKAE6ki6JUyI1xDwrYiwkT8VwpGUBKgX4pQ8v0Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OL6FVuPJEn01ZNO3ExQhd61uDTAxSUxSjXRdnHhVRHA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceSkatingSports/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceSkatingSports"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I-aciKAE6ki6JUyI1xDwrYiwkT8VwpGUBKgX4pQ8v0Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OL6FVuPJEn01ZNO3ExQhd61uDTAxSUxSjXRdnHhVRHA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceSkatingSports/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceSkatingSports"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I-aciKAE6ki6JUyI1xDwrYiwkT8VwpGUBKgX4pQ8v0Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OL6FVuPJEn01ZNO3ExQhd61uDTAxSUxSjXRdnHhVRHA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceSkatingSports/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceSkatingSports"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I-aciKAE6ki6JUyI1xDwrYiwkT8VwpGUBKgX4pQ8v0Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OL6FVuPJEn01ZNO3ExQhd61uDTAxSUxSjXRdnHhVRHA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceSkatingSports/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceSkatingSports"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I-aciKAE6ki6JUyI1xDwrYiwkT8VwpGUBKgX4pQ8v0Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OL6FVuPJEn01ZNO3ExQhd61uDTAxSUxSjXRdnHhVRHA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceSkatingSports/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceSkatingSports"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I-aciKAE6ki6JUyI1xDwrYiwkT8VwpGUBKgX4pQ8v0Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OL6FVuPJEn01ZNO3ExQhd61uDTAxSUxSjXRdnHhVRHA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceSkatingSports/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceSkatingSports, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceSkatingSports/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceSkatingSports, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceSkatingSports/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceSkatingSports, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceSwimming/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceSwimming"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:tep5D3Us-e8m-PoQ2w7LCTGTM_muW7BjLSVXDZrXZHM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4ESrLdSkiVJOKvjY4BIdbrkEzq0bfvCd1LFlkfDG4GM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceSwimming/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceSwimming"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:tep5D3Us-e8m-PoQ2w7LCTGTM_muW7BjLSVXDZrXZHM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4ESrLdSkiVJOKvjY4BIdbrkEzq0bfvCd1LFlkfDG4GM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceSwimming/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceSwimming"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:tep5D3Us-e8m-PoQ2w7LCTGTM_muW7BjLSVXDZrXZHM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4ESrLdSkiVJOKvjY4BIdbrkEzq0bfvCd1LFlkfDG4GM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceSwimming/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceSwimming"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:tep5D3Us-e8m-PoQ2w7LCTGTM_muW7BjLSVXDZrXZHM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4ESrLdSkiVJOKvjY4BIdbrkEzq0bfvCd1LFlkfDG4GM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceSwimming/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceSwimming"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:tep5D3Us-e8m-PoQ2w7LCTGTM_muW7BjLSVXDZrXZHM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4ESrLdSkiVJOKvjY4BIdbrkEzq0bfvCd1LFlkfDG4GM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceSwimming/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceSwimming"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:tep5D3Us-e8m-PoQ2w7LCTGTM_muW7BjLSVXDZrXZHM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4ESrLdSkiVJOKvjY4BIdbrkEzq0bfvCd1LFlkfDG4GM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceSwimming/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceSwimming, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceSwimming/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceSwimming, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceSwimming/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceSwimming, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceWalkingRunning/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceWalkingRunning"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3Qajiutsfq1QhnxWicNQzAxIUxpvbqvfBwg2Tqm_9VA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:L5qkCNAKPXMoI40QRPkJH7egfW0sMsSLD53NAc-lWLY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceWalkingRunning/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceWalkingRunning"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3Qajiutsfq1QhnxWicNQzAxIUxpvbqvfBwg2Tqm_9VA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:L5qkCNAKPXMoI40QRPkJH7egfW0sMsSLD53NAc-lWLY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceWalkingRunning/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceWalkingRunning"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3Qajiutsfq1QhnxWicNQzAxIUxpvbqvfBwg2Tqm_9VA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:L5qkCNAKPXMoI40QRPkJH7egfW0sMsSLD53NAc-lWLY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceWalkingRunning/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceWalkingRunning"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3Qajiutsfq1QhnxWicNQzAxIUxpvbqvfBwg2Tqm_9VA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:L5qkCNAKPXMoI40QRPkJH7egfW0sMsSLD53NAc-lWLY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceWalkingRunning/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceWalkingRunning"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3Qajiutsfq1QhnxWicNQzAxIUxpvbqvfBwg2Tqm_9VA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:L5qkCNAKPXMoI40QRPkJH7egfW0sMsSLD53NAc-lWLY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceWalkingRunning/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceWalkingRunning"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3Qajiutsfq1QhnxWicNQzAxIUxpvbqvfBwg2Tqm_9VA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:L5qkCNAKPXMoI40QRPkJH7egfW0sMsSLD53NAc-lWLY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceWalkingRunning/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceWalkingRunning, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceWalkingRunning/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceWalkingRunning, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceWalkingRunning/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceWalkingRunning, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceWheelchair/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceWheelchair"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Bl00hhOc-Lb3EX5D6IHumPGUUHZg2a3gvyVgVyuJQwE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:My_5i5foD-eWXcYJRwP16nT2YlJp4BdylhGb8muc4cU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceWheelchair/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceWheelchair"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Bl00hhOc-Lb3EX5D6IHumPGUUHZg2a3gvyVgVyuJQwE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:My_5i5foD-eWXcYJRwP16nT2YlJp4BdylhGb8muc4cU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceWheelchair/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceWheelchair"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Bl00hhOc-Lb3EX5D6IHumPGUUHZg2a3gvyVgVyuJQwE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:My_5i5foD-eWXcYJRwP16nT2YlJp4BdylhGb8muc4cU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceWheelchair/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceWheelchair"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Bl00hhOc-Lb3EX5D6IHumPGUUHZg2a3gvyVgVyuJQwE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:My_5i5foD-eWXcYJRwP16nT2YlJp4BdylhGb8muc4cU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceWheelchair/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceWheelchair"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Bl00hhOc-Lb3EX5D6IHumPGUUHZg2a3gvyVgVyuJQwE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:My_5i5foD-eWXcYJRwP16nT2YlJp4BdylhGb8muc4cU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceWheelchair/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"103208-5","display":"Distance traveled","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDistanceWheelchair"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Bl00hhOc-Lb3EX5D6IHumPGUUHZg2a3gvyVgVyuJQwE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:My_5i5foD-eWXcYJRwP16nT2YlJp4BdylhGb8muc4cU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceWheelchair/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceWheelchair, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceWheelchair/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceWheelchair, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierDistanceWheelchair/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.distanceWheelchair, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierElectrodermalActivity/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierElectrodermalActivity","unit":"mcS","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"electrodermal-activity","display":"Electrodermal activity","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierElectrodermalActivity"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-dWwS5Q2N2cRvezyT7whOZlEsK3RC3eNxMx_zlIQcKY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I0dfsTlDV7cS3ou5tJMEYOC9Cq4qGmGgb9pQJZnwH_g"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-electrodermal-activity","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"uS","system":"http://unitsofmeasure.org","unit":"uS","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierElectrodermalActivity/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierElectrodermalActivity","unit":"mcS","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"electrodermal-activity","display":"Electrodermal activity","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierElectrodermalActivity"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-dWwS5Q2N2cRvezyT7whOZlEsK3RC3eNxMx_zlIQcKY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I0dfsTlDV7cS3ou5tJMEYOC9Cq4qGmGgb9pQJZnwH_g"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-electrodermal-activity","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"uS","system":"http://unitsofmeasure.org","unit":"uS","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierElectrodermalActivity/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierElectrodermalActivity","unit":"mcS","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"electrodermal-activity","display":"Electrodermal activity","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierElectrodermalActivity"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-dWwS5Q2N2cRvezyT7whOZlEsK3RC3eNxMx_zlIQcKY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I0dfsTlDV7cS3ou5tJMEYOC9Cq4qGmGgb9pQJZnwH_g"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-electrodermal-activity","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"uS","system":"http://unitsofmeasure.org","unit":"uS","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierElectrodermalActivity/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierElectrodermalActivity","unit":"mcS","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"electrodermal-activity","display":"Electrodermal activity","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierElectrodermalActivity"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-dWwS5Q2N2cRvezyT7whOZlEsK3RC3eNxMx_zlIQcKY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I0dfsTlDV7cS3ou5tJMEYOC9Cq4qGmGgb9pQJZnwH_g"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-electrodermal-activity","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"uS","system":"http://unitsofmeasure.org","unit":"uS","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierElectrodermalActivity/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierElectrodermalActivity","unit":"mcS","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"electrodermal-activity","display":"Electrodermal activity","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierElectrodermalActivity"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-dWwS5Q2N2cRvezyT7whOZlEsK3RC3eNxMx_zlIQcKY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I0dfsTlDV7cS3ou5tJMEYOC9Cq4qGmGgb9pQJZnwH_g"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-electrodermal-activity","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"uS","system":"http://unitsofmeasure.org","unit":"uS","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierElectrodermalActivity/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierElectrodermalActivity","unit":"mcS","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"electrodermal-activity","display":"Electrodermal activity","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierElectrodermalActivity"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-dWwS5Q2N2cRvezyT7whOZlEsK3RC3eNxMx_zlIQcKY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:I0dfsTlDV7cS3ou5tJMEYOC9Cq4qGmGgb9pQJZnwH_g"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-electrodermal-activity","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"uS","system":"http://unitsofmeasure.org","unit":"uS","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierElectrodermalActivity/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierElectrodermalActivity","unit":"mcS","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.electrodermalActivity, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierElectrodermalActivity/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierElectrodermalActivity","unit":"mcS","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.electrodermalActivity, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierElectrodermalActivity/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierElectrodermalActivity","unit":"mcS","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.electrodermalActivity, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierEnvironmentalAudioExposure/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEnvironmentalAudioExposure","unit":"dBASPL","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"environmental-audio-exposure","display":"Environmental audio exposure","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierEnvironmentalAudioExposure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:K6l6X1t_yCw36_sNXl276vqxmPD11aFAICxTPFsLLuQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:RfL4MJl3uYaXpJhEXOKYOULzNfc03GSSBlkXIznl5Rw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-environmental-audio-exposure"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"dB[SPL]","system":"http://unitsofmeasure.org","unit":"dB(SPL)","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierEnvironmentalAudioExposure/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEnvironmentalAudioExposure","unit":"dBASPL","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"environmental-audio-exposure","display":"Environmental audio exposure","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierEnvironmentalAudioExposure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:K6l6X1t_yCw36_sNXl276vqxmPD11aFAICxTPFsLLuQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:RfL4MJl3uYaXpJhEXOKYOULzNfc03GSSBlkXIznl5Rw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-environmental-audio-exposure"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"dB[SPL]","system":"http://unitsofmeasure.org","unit":"dB(SPL)","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierEnvironmentalAudioExposure/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEnvironmentalAudioExposure","unit":"dBASPL","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"environmental-audio-exposure","display":"Environmental audio exposure","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierEnvironmentalAudioExposure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:K6l6X1t_yCw36_sNXl276vqxmPD11aFAICxTPFsLLuQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:RfL4MJl3uYaXpJhEXOKYOULzNfc03GSSBlkXIznl5Rw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-environmental-audio-exposure"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"dB[SPL]","system":"http://unitsofmeasure.org","unit":"dB(SPL)","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierEnvironmentalAudioExposure/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEnvironmentalAudioExposure","unit":"dBASPL","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"environmental-audio-exposure","display":"Environmental audio exposure","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierEnvironmentalAudioExposure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:K6l6X1t_yCw36_sNXl276vqxmPD11aFAICxTPFsLLuQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:RfL4MJl3uYaXpJhEXOKYOULzNfc03GSSBlkXIznl5Rw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-environmental-audio-exposure"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"dB[SPL]","system":"http://unitsofmeasure.org","unit":"dB(SPL)","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierEnvironmentalAudioExposure/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEnvironmentalAudioExposure","unit":"dBASPL","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"environmental-audio-exposure","display":"Environmental audio exposure","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierEnvironmentalAudioExposure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:K6l6X1t_yCw36_sNXl276vqxmPD11aFAICxTPFsLLuQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:RfL4MJl3uYaXpJhEXOKYOULzNfc03GSSBlkXIznl5Rw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-environmental-audio-exposure"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"dB[SPL]","system":"http://unitsofmeasure.org","unit":"dB(SPL)","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierEnvironmentalAudioExposure/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEnvironmentalAudioExposure","unit":"dBASPL","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"environmental-audio-exposure","display":"Environmental audio exposure","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierEnvironmentalAudioExposure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:K6l6X1t_yCw36_sNXl276vqxmPD11aFAICxTPFsLLuQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:RfL4MJl3uYaXpJhEXOKYOULzNfc03GSSBlkXIznl5Rw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-environmental-audio-exposure"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"dB[SPL]","system":"http://unitsofmeasure.org","unit":"dB(SPL)","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierEnvironmentalAudioExposure/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEnvironmentalAudioExposure","unit":"dBASPL","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.environmentalAudioExposure, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierEnvironmentalAudioExposure/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEnvironmentalAudioExposure","unit":"dBASPL","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.environmentalAudioExposure, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierEnvironmentalAudioExposure/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEnvironmentalAudioExposure","unit":"dBASPL","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.environmentalAudioExposure, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierEnvironmentalSoundReduction/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEnvironmentalSoundReduction","unit":"dBASPL","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"environmental-sound-reduction","display":"Environmental sound reduction","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierEnvironmentalSoundReduction"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:8ombFBTAX6m1FQuWDvuNQ5HmDmB6WWUkl2mJCGfFkqk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:97_ahzSKvvPVUhbNty4fuPnZKgJZo3GR8JyHGrI4UBA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-environmental-sound-reduction"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"dB[SPL]","system":"http://unitsofmeasure.org","unit":"dB(SPL)","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierEnvironmentalSoundReduction/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEnvironmentalSoundReduction","unit":"dBASPL","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"environmental-sound-reduction","display":"Environmental sound reduction","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierEnvironmentalSoundReduction"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:8ombFBTAX6m1FQuWDvuNQ5HmDmB6WWUkl2mJCGfFkqk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:97_ahzSKvvPVUhbNty4fuPnZKgJZo3GR8JyHGrI4UBA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-environmental-sound-reduction"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"dB[SPL]","system":"http://unitsofmeasure.org","unit":"dB(SPL)","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierEnvironmentalSoundReduction/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEnvironmentalSoundReduction","unit":"dBASPL","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"environmental-sound-reduction","display":"Environmental sound reduction","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierEnvironmentalSoundReduction"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:8ombFBTAX6m1FQuWDvuNQ5HmDmB6WWUkl2mJCGfFkqk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:97_ahzSKvvPVUhbNty4fuPnZKgJZo3GR8JyHGrI4UBA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-environmental-sound-reduction"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"dB[SPL]","system":"http://unitsofmeasure.org","unit":"dB(SPL)","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierEnvironmentalSoundReduction/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEnvironmentalSoundReduction","unit":"dBASPL","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"environmental-sound-reduction","display":"Environmental sound reduction","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierEnvironmentalSoundReduction"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:8ombFBTAX6m1FQuWDvuNQ5HmDmB6WWUkl2mJCGfFkqk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:97_ahzSKvvPVUhbNty4fuPnZKgJZo3GR8JyHGrI4UBA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-environmental-sound-reduction"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"dB[SPL]","system":"http://unitsofmeasure.org","unit":"dB(SPL)","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierEnvironmentalSoundReduction/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEnvironmentalSoundReduction","unit":"dBASPL","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"environmental-sound-reduction","display":"Environmental sound reduction","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierEnvironmentalSoundReduction"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:8ombFBTAX6m1FQuWDvuNQ5HmDmB6WWUkl2mJCGfFkqk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:97_ahzSKvvPVUhbNty4fuPnZKgJZo3GR8JyHGrI4UBA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-environmental-sound-reduction"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"dB[SPL]","system":"http://unitsofmeasure.org","unit":"dB(SPL)","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierEnvironmentalSoundReduction/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEnvironmentalSoundReduction","unit":"dBASPL","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"environmental-sound-reduction","display":"Environmental sound reduction","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierEnvironmentalSoundReduction"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:8ombFBTAX6m1FQuWDvuNQ5HmDmB6WWUkl2mJCGfFkqk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:97_ahzSKvvPVUhbNty4fuPnZKgJZo3GR8JyHGrI4UBA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-environmental-sound-reduction"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"dB[SPL]","system":"http://unitsofmeasure.org","unit":"dB(SPL)","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierEnvironmentalSoundReduction/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEnvironmentalSoundReduction","unit":"dBASPL","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.environmentalSoundReduction, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierEnvironmentalSoundReduction/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEnvironmentalSoundReduction","unit":"dBASPL","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.environmentalSoundReduction, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierEnvironmentalSoundReduction/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEnvironmentalSoundReduction","unit":"dBASPL","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.environmentalSoundReduction, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierEstimatedWorkoutEffortScore/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEstimatedWorkoutEffortScore","unit":"appleEffortScore","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout-effort-score","display":"Workout effort score","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierEstimatedWorkoutEffortScore"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:l9eE-8Udnh2_6gLJniKFzhAf5pravn1r7nwKcSKisMw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ENSe1mUZC3sdttsbkZD_nvMNiwNQtHQ3DIevzfWR2No"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-workout-effort-score"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{score}","system":"http://unitsofmeasure.org","unit":"score","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierEstimatedWorkoutEffortScore/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEstimatedWorkoutEffortScore","unit":"appleEffortScore","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout-effort-score","display":"Workout effort score","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierEstimatedWorkoutEffortScore"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:l9eE-8Udnh2_6gLJniKFzhAf5pravn1r7nwKcSKisMw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ENSe1mUZC3sdttsbkZD_nvMNiwNQtHQ3DIevzfWR2No"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-workout-effort-score"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{score}","system":"http://unitsofmeasure.org","unit":"score","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierEstimatedWorkoutEffortScore/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEstimatedWorkoutEffortScore","unit":"appleEffortScore","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout-effort-score","display":"Workout effort score","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierEstimatedWorkoutEffortScore"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:l9eE-8Udnh2_6gLJniKFzhAf5pravn1r7nwKcSKisMw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ENSe1mUZC3sdttsbkZD_nvMNiwNQtHQ3DIevzfWR2No"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-workout-effort-score"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{score}","system":"http://unitsofmeasure.org","unit":"score","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierEstimatedWorkoutEffortScore/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEstimatedWorkoutEffortScore","unit":"appleEffortScore","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout-effort-score","display":"Workout effort score","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierEstimatedWorkoutEffortScore"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:l9eE-8Udnh2_6gLJniKFzhAf5pravn1r7nwKcSKisMw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ENSe1mUZC3sdttsbkZD_nvMNiwNQtHQ3DIevzfWR2No"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-workout-effort-score"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{score}","system":"http://unitsofmeasure.org","unit":"score","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierEstimatedWorkoutEffortScore/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEstimatedWorkoutEffortScore","unit":"appleEffortScore","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout-effort-score","display":"Workout effort score","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierEstimatedWorkoutEffortScore"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:l9eE-8Udnh2_6gLJniKFzhAf5pravn1r7nwKcSKisMw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ENSe1mUZC3sdttsbkZD_nvMNiwNQtHQ3DIevzfWR2No"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-workout-effort-score"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{score}","system":"http://unitsofmeasure.org","unit":"score","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierEstimatedWorkoutEffortScore/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEstimatedWorkoutEffortScore","unit":"appleEffortScore","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout-effort-score","display":"Workout effort score","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierEstimatedWorkoutEffortScore"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:l9eE-8Udnh2_6gLJniKFzhAf5pravn1r7nwKcSKisMw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ENSe1mUZC3sdttsbkZD_nvMNiwNQtHQ3DIevzfWR2No"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-workout-effort-score"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{score}","system":"http://unitsofmeasure.org","unit":"score","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierEstimatedWorkoutEffortScore/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEstimatedWorkoutEffortScore","unit":"appleEffortScore","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.estimatedWorkoutEffortScore, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierEstimatedWorkoutEffortScore/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEstimatedWorkoutEffortScore","unit":"appleEffortScore","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.estimatedWorkoutEffortScore, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierEstimatedWorkoutEffortScore/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierEstimatedWorkoutEffortScore","unit":"appleEffortScore","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.estimatedWorkoutEffortScore, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierFlightsClimbed/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierFlightsClimbed","unit":"count","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"100304-5","display":"Flights climbed [#] Reporting Period","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierFlightsClimbed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:r9a7LgrgziOBQZ5DotULjCsPqxmKBOYlVS0xKZYrmN4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YHDQhzkmx-9QO2lMmmRZbCyfmi6p08PzP5NZhHSugDA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-flights-climbed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{flights}","system":"http://unitsofmeasure.org","unit":"flights","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierFlightsClimbed/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierFlightsClimbed","unit":"count","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"100304-5","display":"Flights climbed [#] Reporting Period","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierFlightsClimbed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:r9a7LgrgziOBQZ5DotULjCsPqxmKBOYlVS0xKZYrmN4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YHDQhzkmx-9QO2lMmmRZbCyfmi6p08PzP5NZhHSugDA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-flights-climbed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{flights}","system":"http://unitsofmeasure.org","unit":"flights","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierFlightsClimbed/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierFlightsClimbed","unit":"count","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.flightsClimbed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierFlightsClimbed/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierFlightsClimbed","unit":"count","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.flightsClimbed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierFlightsClimbed/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierFlightsClimbed","unit":"count","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.flightsClimbed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierFlightsClimbed/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierFlightsClimbed","unit":"count","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"100304-5","display":"Flights climbed [#] Reporting Period","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierFlightsClimbed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:r9a7LgrgziOBQZ5DotULjCsPqxmKBOYlVS0xKZYrmN4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YHDQhzkmx-9QO2lMmmRZbCyfmi6p08PzP5NZhHSugDA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-flights-climbed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{flights}","system":"http://unitsofmeasure.org","unit":"flights","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierFlightsClimbed/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierFlightsClimbed","unit":"count","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.flightsClimbed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierFlightsClimbed/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierFlightsClimbed","unit":"count","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.flightsClimbed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierFlightsClimbed/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierFlightsClimbed","unit":"count","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.flightsClimbed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierForcedExpiratoryVolume1/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierForcedExpiratoryVolume1","unit":"L","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"20150-9","display":"FEV1","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierForcedExpiratoryVolume1"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ddfGnbna75Geww8RgcunCOdEpcGeBi6TxLuH4iPX_zw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:z8EOWpmonl3DbN_vIKa4g7brtrWFVTmGQe0ZEBL4fQQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-forced-expiratory-volume-1"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"L","system":"http://unitsofmeasure.org","unit":"L","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierForcedExpiratoryVolume1/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierForcedExpiratoryVolume1","unit":"L","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"20150-9","display":"FEV1","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierForcedExpiratoryVolume1"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ddfGnbna75Geww8RgcunCOdEpcGeBi6TxLuH4iPX_zw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:z8EOWpmonl3DbN_vIKa4g7brtrWFVTmGQe0ZEBL4fQQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-forced-expiratory-volume-1"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"L","system":"http://unitsofmeasure.org","unit":"L","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierForcedExpiratoryVolume1/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierForcedExpiratoryVolume1","unit":"L","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"20150-9","display":"FEV1","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierForcedExpiratoryVolume1"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ddfGnbna75Geww8RgcunCOdEpcGeBi6TxLuH4iPX_zw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:z8EOWpmonl3DbN_vIKa4g7brtrWFVTmGQe0ZEBL4fQQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-forced-expiratory-volume-1"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"L","system":"http://unitsofmeasure.org","unit":"L","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierForcedExpiratoryVolume1/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierForcedExpiratoryVolume1","unit":"L","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"20150-9","display":"FEV1","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierForcedExpiratoryVolume1"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ddfGnbna75Geww8RgcunCOdEpcGeBi6TxLuH4iPX_zw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:z8EOWpmonl3DbN_vIKa4g7brtrWFVTmGQe0ZEBL4fQQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-forced-expiratory-volume-1"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"L","system":"http://unitsofmeasure.org","unit":"L","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierForcedExpiratoryVolume1/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierForcedExpiratoryVolume1","unit":"L","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"20150-9","display":"FEV1","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierForcedExpiratoryVolume1"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ddfGnbna75Geww8RgcunCOdEpcGeBi6TxLuH4iPX_zw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:z8EOWpmonl3DbN_vIKa4g7brtrWFVTmGQe0ZEBL4fQQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-forced-expiratory-volume-1"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"L","system":"http://unitsofmeasure.org","unit":"L","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierForcedExpiratoryVolume1/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierForcedExpiratoryVolume1","unit":"L","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"20150-9","display":"FEV1","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierForcedExpiratoryVolume1"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ddfGnbna75Geww8RgcunCOdEpcGeBi6TxLuH4iPX_zw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:z8EOWpmonl3DbN_vIKa4g7brtrWFVTmGQe0ZEBL4fQQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-forced-expiratory-volume-1"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"L","system":"http://unitsofmeasure.org","unit":"L","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierForcedExpiratoryVolume1/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierForcedExpiratoryVolume1","unit":"L","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.forcedExpiratoryVolume1, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierForcedExpiratoryVolume1/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierForcedExpiratoryVolume1","unit":"L","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.forcedExpiratoryVolume1, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierForcedExpiratoryVolume1/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierForcedExpiratoryVolume1","unit":"L","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.forcedExpiratoryVolume1, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierForcedVitalCapacity/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierForcedVitalCapacity","unit":"L","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"19868-9","display":"Forced vital capacity [Volume] Respiratory system by Spirometry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierForcedVitalCapacity"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gbVf-XaQwNgwiKYl3pOH0vDfZ7faMtUtosvNrtfj20E"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xJQfCdiwEHZ2_MGvfrvawtOxMtcM1fDZG0SYwqR7_2k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-forced-vital-capacity"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"L","system":"http://unitsofmeasure.org","unit":"L","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierForcedVitalCapacity/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierForcedVitalCapacity","unit":"L","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"19868-9","display":"Forced vital capacity [Volume] Respiratory system by Spirometry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierForcedVitalCapacity"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gbVf-XaQwNgwiKYl3pOH0vDfZ7faMtUtosvNrtfj20E"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xJQfCdiwEHZ2_MGvfrvawtOxMtcM1fDZG0SYwqR7_2k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-forced-vital-capacity"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"L","system":"http://unitsofmeasure.org","unit":"L","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierForcedVitalCapacity/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierForcedVitalCapacity","unit":"L","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"19868-9","display":"Forced vital capacity [Volume] Respiratory system by Spirometry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierForcedVitalCapacity"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gbVf-XaQwNgwiKYl3pOH0vDfZ7faMtUtosvNrtfj20E"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xJQfCdiwEHZ2_MGvfrvawtOxMtcM1fDZG0SYwqR7_2k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-forced-vital-capacity"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"L","system":"http://unitsofmeasure.org","unit":"L","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierForcedVitalCapacity/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierForcedVitalCapacity","unit":"L","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"19868-9","display":"Forced vital capacity [Volume] Respiratory system by Spirometry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierForcedVitalCapacity"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gbVf-XaQwNgwiKYl3pOH0vDfZ7faMtUtosvNrtfj20E"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xJQfCdiwEHZ2_MGvfrvawtOxMtcM1fDZG0SYwqR7_2k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-forced-vital-capacity"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"L","system":"http://unitsofmeasure.org","unit":"L","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierForcedVitalCapacity/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierForcedVitalCapacity","unit":"L","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"19868-9","display":"Forced vital capacity [Volume] Respiratory system by Spirometry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierForcedVitalCapacity"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gbVf-XaQwNgwiKYl3pOH0vDfZ7faMtUtosvNrtfj20E"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xJQfCdiwEHZ2_MGvfrvawtOxMtcM1fDZG0SYwqR7_2k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-forced-vital-capacity"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"L","system":"http://unitsofmeasure.org","unit":"L","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierForcedVitalCapacity/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierForcedVitalCapacity","unit":"L","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"19868-9","display":"Forced vital capacity [Volume] Respiratory system by Spirometry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierForcedVitalCapacity"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gbVf-XaQwNgwiKYl3pOH0vDfZ7faMtUtosvNrtfj20E"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xJQfCdiwEHZ2_MGvfrvawtOxMtcM1fDZG0SYwqR7_2k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-forced-vital-capacity"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"L","system":"http://unitsofmeasure.org","unit":"L","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierForcedVitalCapacity/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierForcedVitalCapacity","unit":"L","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.forcedVitalCapacity, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierForcedVitalCapacity/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierForcedVitalCapacity","unit":"L","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.forcedVitalCapacity, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierForcedVitalCapacity/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierForcedVitalCapacity","unit":"L","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.forcedVitalCapacity, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierHeadphoneAudioExposure/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeadphoneAudioExposure","unit":"dBASPL","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"headphone-audio-exposure","display":"Headphone audio exposure","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeadphoneAudioExposure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:25sjbFDMIQYIAxELC5VsNW-fKzSCEMDOqS6P-dVL6uw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:oqkE2zn9ewaKw-kwVsfmfhaQ9y4ZRueSIYOZjpuYego"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-headphone-audio-exposure"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"dB[SPL]","system":"http://unitsofmeasure.org","unit":"dB(SPL)","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeadphoneAudioExposure/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeadphoneAudioExposure","unit":"dBASPL","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"headphone-audio-exposure","display":"Headphone audio exposure","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeadphoneAudioExposure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:25sjbFDMIQYIAxELC5VsNW-fKzSCEMDOqS6P-dVL6uw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:oqkE2zn9ewaKw-kwVsfmfhaQ9y4ZRueSIYOZjpuYego"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-headphone-audio-exposure"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"dB[SPL]","system":"http://unitsofmeasure.org","unit":"dB(SPL)","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeadphoneAudioExposure/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeadphoneAudioExposure","unit":"dBASPL","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"headphone-audio-exposure","display":"Headphone audio exposure","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeadphoneAudioExposure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:25sjbFDMIQYIAxELC5VsNW-fKzSCEMDOqS6P-dVL6uw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:oqkE2zn9ewaKw-kwVsfmfhaQ9y4ZRueSIYOZjpuYego"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-headphone-audio-exposure"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"dB[SPL]","system":"http://unitsofmeasure.org","unit":"dB(SPL)","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeadphoneAudioExposure/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeadphoneAudioExposure","unit":"dBASPL","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"headphone-audio-exposure","display":"Headphone audio exposure","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeadphoneAudioExposure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:25sjbFDMIQYIAxELC5VsNW-fKzSCEMDOqS6P-dVL6uw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:oqkE2zn9ewaKw-kwVsfmfhaQ9y4ZRueSIYOZjpuYego"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-headphone-audio-exposure"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"dB[SPL]","system":"http://unitsofmeasure.org","unit":"dB(SPL)","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeadphoneAudioExposure/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeadphoneAudioExposure","unit":"dBASPL","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"headphone-audio-exposure","display":"Headphone audio exposure","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeadphoneAudioExposure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:25sjbFDMIQYIAxELC5VsNW-fKzSCEMDOqS6P-dVL6uw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:oqkE2zn9ewaKw-kwVsfmfhaQ9y4ZRueSIYOZjpuYego"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-headphone-audio-exposure"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"dB[SPL]","system":"http://unitsofmeasure.org","unit":"dB(SPL)","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeadphoneAudioExposure/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeadphoneAudioExposure","unit":"dBASPL","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"headphone-audio-exposure","display":"Headphone audio exposure","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeadphoneAudioExposure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:25sjbFDMIQYIAxELC5VsNW-fKzSCEMDOqS6P-dVL6uw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:oqkE2zn9ewaKw-kwVsfmfhaQ9y4ZRueSIYOZjpuYego"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-headphone-audio-exposure"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"dB[SPL]","system":"http://unitsofmeasure.org","unit":"dB(SPL)","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeadphoneAudioExposure/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeadphoneAudioExposure","unit":"dBASPL","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.headphoneAudioExposure, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierHeadphoneAudioExposure/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeadphoneAudioExposure","unit":"dBASPL","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.headphoneAudioExposure, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierHeadphoneAudioExposure/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeadphoneAudioExposure","unit":"dBASPL","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.headphoneAudioExposure, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRate/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRate/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRate/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRate/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRate/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRate/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRate/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRate/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRate/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRateRecoveryOneMinute/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRateRecoveryOneMinute","unit":"count/min","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"heart-rate-recovery-one-minute","display":"Heart rate recovery one minute","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRateRecoveryOneMinute"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:f5xJBul_vUvj4-AkmWCGHcmfYgw4Mqd08ivDHk6ALJw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Z6bHoOO_Lf6KajuX_0ntb8ZmE2QuMEfWIqWBXemDS2g"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-heart-rate-recovery-one-minute"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRateRecoveryOneMinute/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRateRecoveryOneMinute","unit":"count/min","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"heart-rate-recovery-one-minute","display":"Heart rate recovery one minute","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRateRecoveryOneMinute"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:f5xJBul_vUvj4-AkmWCGHcmfYgw4Mqd08ivDHk6ALJw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Z6bHoOO_Lf6KajuX_0ntb8ZmE2QuMEfWIqWBXemDS2g"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-heart-rate-recovery-one-minute"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRateRecoveryOneMinute/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRateRecoveryOneMinute","unit":"count/min","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"heart-rate-recovery-one-minute","display":"Heart rate recovery one minute","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRateRecoveryOneMinute"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:f5xJBul_vUvj4-AkmWCGHcmfYgw4Mqd08ivDHk6ALJw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Z6bHoOO_Lf6KajuX_0ntb8ZmE2QuMEfWIqWBXemDS2g"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-heart-rate-recovery-one-minute"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRateRecoveryOneMinute/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRateRecoveryOneMinute","unit":"count/min","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"heart-rate-recovery-one-minute","display":"Heart rate recovery one minute","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRateRecoveryOneMinute"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:f5xJBul_vUvj4-AkmWCGHcmfYgw4Mqd08ivDHk6ALJw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Z6bHoOO_Lf6KajuX_0ntb8ZmE2QuMEfWIqWBXemDS2g"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-heart-rate-recovery-one-minute"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRateRecoveryOneMinute/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRateRecoveryOneMinute","unit":"count/min","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"heart-rate-recovery-one-minute","display":"Heart rate recovery one minute","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRateRecoveryOneMinute"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:f5xJBul_vUvj4-AkmWCGHcmfYgw4Mqd08ivDHk6ALJw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Z6bHoOO_Lf6KajuX_0ntb8ZmE2QuMEfWIqWBXemDS2g"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-heart-rate-recovery-one-minute"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRateRecoveryOneMinute/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRateRecoveryOneMinute","unit":"count/min","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"heart-rate-recovery-one-minute","display":"Heart rate recovery one minute","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRateRecoveryOneMinute"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:f5xJBul_vUvj4-AkmWCGHcmfYgw4Mqd08ivDHk6ALJw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Z6bHoOO_Lf6KajuX_0ntb8ZmE2QuMEfWIqWBXemDS2g"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-heart-rate-recovery-one-minute"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRateRecoveryOneMinute/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRateRecoveryOneMinute","unit":"count/min","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRateRecoveryOneMinute, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRateRecoveryOneMinute/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRateRecoveryOneMinute","unit":"count/min","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRateRecoveryOneMinute, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRateRecoveryOneMinute/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRateRecoveryOneMinute","unit":"count/min","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRateRecoveryOneMinute, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRateVariabilitySDNN/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRateVariabilitySDNN","unit":"ms","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112429-6","display":"Heart rate variability SDNN [Time]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRateVariabilitySDNN"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:eM7zcov-lMa9FBa7iiUkIgiC_w-8tnl6OTjGyVGGFEA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pGuhDq-GtlpOi8sY0hpcHW1OjPe8kOUnVa_na0LwDCA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate-variability-sdnn","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ms","system":"http://unitsofmeasure.org","unit":"ms","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRateVariabilitySDNN/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRateVariabilitySDNN","unit":"ms","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112429-6","display":"Heart rate variability SDNN [Time]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRateVariabilitySDNN"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:eM7zcov-lMa9FBa7iiUkIgiC_w-8tnl6OTjGyVGGFEA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pGuhDq-GtlpOi8sY0hpcHW1OjPe8kOUnVa_na0LwDCA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate-variability-sdnn","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ms","system":"http://unitsofmeasure.org","unit":"ms","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRateVariabilitySDNN/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRateVariabilitySDNN","unit":"ms","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112429-6","display":"Heart rate variability SDNN [Time]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRateVariabilitySDNN"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:eM7zcov-lMa9FBa7iiUkIgiC_w-8tnl6OTjGyVGGFEA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pGuhDq-GtlpOi8sY0hpcHW1OjPe8kOUnVa_na0LwDCA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate-variability-sdnn","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ms","system":"http://unitsofmeasure.org","unit":"ms","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRateVariabilitySDNN/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRateVariabilitySDNN","unit":"ms","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112429-6","display":"Heart rate variability SDNN [Time]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRateVariabilitySDNN"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:eM7zcov-lMa9FBa7iiUkIgiC_w-8tnl6OTjGyVGGFEA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pGuhDq-GtlpOi8sY0hpcHW1OjPe8kOUnVa_na0LwDCA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate-variability-sdnn","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ms","system":"http://unitsofmeasure.org","unit":"ms","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRateVariabilitySDNN/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRateVariabilitySDNN","unit":"ms","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112429-6","display":"Heart rate variability SDNN [Time]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRateVariabilitySDNN"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:eM7zcov-lMa9FBa7iiUkIgiC_w-8tnl6OTjGyVGGFEA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pGuhDq-GtlpOi8sY0hpcHW1OjPe8kOUnVa_na0LwDCA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate-variability-sdnn","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ms","system":"http://unitsofmeasure.org","unit":"ms","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRateVariabilitySDNN/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRateVariabilitySDNN","unit":"ms","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112429-6","display":"Heart rate variability SDNN [Time]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRateVariabilitySDNN"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:eM7zcov-lMa9FBa7iiUkIgiC_w-8tnl6OTjGyVGGFEA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pGuhDq-GtlpOi8sY0hpcHW1OjPe8kOUnVa_na0LwDCA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate-variability-sdnn","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ms","system":"http://unitsofmeasure.org","unit":"ms","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRateVariabilitySDNN/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRateVariabilitySDNN","unit":"ms","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRateVariabilitySDNN, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRateVariabilitySDNN/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRateVariabilitySDNN","unit":"ms","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRateVariabilitySDNN, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierHeartRateVariabilitySDNN/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRateVariabilitySDNN","unit":"ms","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRateVariabilitySDNN, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierHeight/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeight","unit":"cm","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8302-2","display":"Body height","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeight"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yH5io7n8U2tq5O3EwuzTPGOoiRyGAdrPqxm7cS3Pgdw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Q8jZlbF4OZJEVGJdQdRShIPnG4cpu7Hcbnctee2vEoE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-height","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeight/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeight","unit":"cm","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8302-2","display":"Body height","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeight"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yH5io7n8U2tq5O3EwuzTPGOoiRyGAdrPqxm7cS3Pgdw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Q8jZlbF4OZJEVGJdQdRShIPnG4cpu7Hcbnctee2vEoE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-height","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeight/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeight","unit":"cm","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8302-2","display":"Body height","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeight"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yH5io7n8U2tq5O3EwuzTPGOoiRyGAdrPqxm7cS3Pgdw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Q8jZlbF4OZJEVGJdQdRShIPnG4cpu7Hcbnctee2vEoE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-height","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeight/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeight","unit":"cm","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8302-2","display":"Body height","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeight"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yH5io7n8U2tq5O3EwuzTPGOoiRyGAdrPqxm7cS3Pgdw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Q8jZlbF4OZJEVGJdQdRShIPnG4cpu7Hcbnctee2vEoE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-height","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeight/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeight","unit":"cm","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8302-2","display":"Body height","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeight"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yH5io7n8U2tq5O3EwuzTPGOoiRyGAdrPqxm7cS3Pgdw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Q8jZlbF4OZJEVGJdQdRShIPnG4cpu7Hcbnctee2vEoE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-height","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeight/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeight","unit":"cm","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8302-2","display":"Body height","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeight"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yH5io7n8U2tq5O3EwuzTPGOoiRyGAdrPqxm7cS3Pgdw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Q8jZlbF4OZJEVGJdQdRShIPnG4cpu7Hcbnctee2vEoE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-height","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierHeight/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeight","unit":"cm","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.height, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierHeight/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeight","unit":"cm","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.height, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierHeight/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeight","unit":"cm","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.height, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierInhalerUsage/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInhalerUsage","unit":"count","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"inhaler-usage","display":"Inhaler usage","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierInhalerUsage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:U7nfIaxkPB2BTlYLvoiTvmfRUm6KNg4IcBQJYdlXol4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Tcsei6Wo1Bax7J1LKYiAsSvkmXjtSwVKp1-RK2XLa38"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-inhaler-usage"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{puff}","system":"http://unitsofmeasure.org","unit":"puffs","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierInhalerUsage/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInhalerUsage","unit":"count","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"inhaler-usage","display":"Inhaler usage","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierInhalerUsage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:U7nfIaxkPB2BTlYLvoiTvmfRUm6KNg4IcBQJYdlXol4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Tcsei6Wo1Bax7J1LKYiAsSvkmXjtSwVKp1-RK2XLa38"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-inhaler-usage"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{puff}","system":"http://unitsofmeasure.org","unit":"puffs","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierInhalerUsage/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInhalerUsage","unit":"count","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.inhalerUsage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierInhalerUsage/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInhalerUsage","unit":"count","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.inhalerUsage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierInhalerUsage/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInhalerUsage","unit":"count","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.inhalerUsage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierInhalerUsage/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInhalerUsage","unit":"count","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"inhaler-usage","display":"Inhaler usage","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierInhalerUsage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:U7nfIaxkPB2BTlYLvoiTvmfRUm6KNg4IcBQJYdlXol4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Tcsei6Wo1Bax7J1LKYiAsSvkmXjtSwVKp1-RK2XLa38"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-inhaler-usage"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{puff}","system":"http://unitsofmeasure.org","unit":"puffs","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierInhalerUsage/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInhalerUsage","unit":"count","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.inhalerUsage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierInhalerUsage/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInhalerUsage","unit":"count","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.inhalerUsage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierInhalerUsage/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInhalerUsage","unit":"count","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.inhalerUsage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierInsulinDelivery/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInsulinDelivery","unit":"IU","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.required-metadata-missing","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.insulinDelivery, GroveHealthKitFHIR.HealthKitValueFailure.requiredMetadataMissing(GroveHealthKitFHIR.HealthKitMetadataField.insulinDeliveryReason))","location":"HKSample.metadata[HKInsulinDeliveryReason]"}}} +{"id":"quantity/HKQuantityTypeIdentifierInsulinDelivery/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInsulinDelivery","unit":"IU","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.required-metadata-missing","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.insulinDelivery, GroveHealthKitFHIR.HealthKitValueFailure.requiredMetadataMissing(GroveHealthKitFHIR.HealthKitMetadataField.insulinDeliveryReason))","location":"HKSample.metadata[HKInsulinDeliveryReason]"}}} +{"id":"quantity/HKQuantityTypeIdentifierInsulinDelivery/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInsulinDelivery","unit":"IU","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.required-metadata-missing","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.insulinDelivery, GroveHealthKitFHIR.HealthKitValueFailure.requiredMetadataMissing(GroveHealthKitFHIR.HealthKitMetadataField.insulinDeliveryReason))","location":"HKSample.metadata[HKInsulinDeliveryReason]"}}} +{"id":"quantity/HKQuantityTypeIdentifierInsulinDelivery/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInsulinDelivery","unit":"IU","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.required-metadata-missing","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.insulinDelivery, GroveHealthKitFHIR.HealthKitValueFailure.requiredMetadataMissing(GroveHealthKitFHIR.HealthKitMetadataField.insulinDeliveryReason))","location":"HKSample.metadata[HKInsulinDeliveryReason]"}}} +{"id":"quantity/HKQuantityTypeIdentifierInsulinDelivery/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInsulinDelivery","unit":"IU","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.required-metadata-missing","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.insulinDelivery, GroveHealthKitFHIR.HealthKitValueFailure.requiredMetadataMissing(GroveHealthKitFHIR.HealthKitMetadataField.insulinDeliveryReason))","location":"HKSample.metadata[HKInsulinDeliveryReason]"}}} +{"id":"quantity/HKQuantityTypeIdentifierInsulinDelivery/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInsulinDelivery","unit":"IU","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.required-metadata-missing","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.insulinDelivery, GroveHealthKitFHIR.HealthKitValueFailure.requiredMetadataMissing(GroveHealthKitFHIR.HealthKitMetadataField.insulinDeliveryReason))","location":"HKSample.metadata[HKInsulinDeliveryReason]"}}} +{"id":"quantity/HKQuantityTypeIdentifierInsulinDelivery/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInsulinDelivery","unit":"IU","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.insulinDelivery, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierInsulinDelivery/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInsulinDelivery","unit":"IU","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.insulinDelivery, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierInsulinDelivery/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInsulinDelivery","unit":"IU","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.insulinDelivery, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierLeanBodyMass/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierLeanBodyMass","unit":"kg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"91557-9","display":"Lean body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierLeanBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yVqivOQugzZ6G1YImkI7jK-zZCBLska1ssgKkS39rwI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VSrpGtie3crVOWrWIsxFTBzDH-G5s0OgICCDu3v-RzM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-lean-body-mass","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierLeanBodyMass/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierLeanBodyMass","unit":"kg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"91557-9","display":"Lean body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierLeanBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yVqivOQugzZ6G1YImkI7jK-zZCBLska1ssgKkS39rwI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VSrpGtie3crVOWrWIsxFTBzDH-G5s0OgICCDu3v-RzM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-lean-body-mass","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierLeanBodyMass/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierLeanBodyMass","unit":"kg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"91557-9","display":"Lean body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierLeanBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yVqivOQugzZ6G1YImkI7jK-zZCBLska1ssgKkS39rwI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VSrpGtie3crVOWrWIsxFTBzDH-G5s0OgICCDu3v-RzM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-lean-body-mass","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierLeanBodyMass/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierLeanBodyMass","unit":"kg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"91557-9","display":"Lean body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierLeanBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yVqivOQugzZ6G1YImkI7jK-zZCBLska1ssgKkS39rwI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VSrpGtie3crVOWrWIsxFTBzDH-G5s0OgICCDu3v-RzM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-lean-body-mass","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierLeanBodyMass/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierLeanBodyMass","unit":"kg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"91557-9","display":"Lean body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierLeanBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yVqivOQugzZ6G1YImkI7jK-zZCBLska1ssgKkS39rwI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VSrpGtie3crVOWrWIsxFTBzDH-G5s0OgICCDu3v-RzM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-lean-body-mass","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierLeanBodyMass/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierLeanBodyMass","unit":"kg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"91557-9","display":"Lean body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierLeanBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yVqivOQugzZ6G1YImkI7jK-zZCBLska1ssgKkS39rwI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VSrpGtie3crVOWrWIsxFTBzDH-G5s0OgICCDu3v-RzM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-lean-body-mass","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierLeanBodyMass/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierLeanBodyMass","unit":"kg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.leanBodyMass, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierLeanBodyMass/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierLeanBodyMass","unit":"kg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.leanBodyMass, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierLeanBodyMass/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierLeanBodyMass","unit":"kg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.leanBodyMass, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierNikeFuel/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNikeFuel","unit":"count","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.intentionally-unsupported-source-type","error":"intentionallyUnsupported(GroveHealthKitFHIR.HealthKitSourceType.nikeFuel, reason: \"NikeFuel is an opaque vendor index with an unpublished formula and a retired ecosystem; it has no physiological dimension, no UCUM representation beyond an arbitrary annotation, and no second source, so normalizing it would launder an undefined score into an exchange measurement.\")","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierNikeFuel/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNikeFuel","unit":"count","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.intentionally-unsupported-source-type","error":"intentionallyUnsupported(GroveHealthKitFHIR.HealthKitSourceType.nikeFuel, reason: \"NikeFuel is an opaque vendor index with an unpublished formula and a retired ecosystem; it has no physiological dimension, no UCUM representation beyond an arbitrary annotation, and no second source, so normalizing it would launder an undefined score into an exchange measurement.\")","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierNikeFuel/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNikeFuel","unit":"count","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.intentionally-unsupported-source-type","error":"intentionallyUnsupported(GroveHealthKitFHIR.HealthKitSourceType.nikeFuel, reason: \"NikeFuel is an opaque vendor index with an unpublished formula and a retired ecosystem; it has no physiological dimension, no UCUM representation beyond an arbitrary annotation, and no second source, so normalizing it would launder an undefined score into an exchange measurement.\")","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierNikeFuel/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNikeFuel","unit":"count","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.intentionally-unsupported-source-type","error":"intentionallyUnsupported(GroveHealthKitFHIR.HealthKitSourceType.nikeFuel, reason: \"NikeFuel is an opaque vendor index with an unpublished formula and a retired ecosystem; it has no physiological dimension, no UCUM representation beyond an arbitrary annotation, and no second source, so normalizing it would launder an undefined score into an exchange measurement.\")","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierNikeFuel/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNikeFuel","unit":"count","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.intentionally-unsupported-source-type","error":"intentionallyUnsupported(GroveHealthKitFHIR.HealthKitSourceType.nikeFuel, reason: \"NikeFuel is an opaque vendor index with an unpublished formula and a retired ecosystem; it has no physiological dimension, no UCUM representation beyond an arbitrary annotation, and no second source, so normalizing it would launder an undefined score into an exchange measurement.\")","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierNikeFuel/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNikeFuel","unit":"count","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.intentionally-unsupported-source-type","error":"intentionallyUnsupported(GroveHealthKitFHIR.HealthKitSourceType.nikeFuel, reason: \"NikeFuel is an opaque vendor index with an unpublished formula and a retired ecosystem; it has no physiological dimension, no UCUM representation beyond an arbitrary annotation, and no second source, so normalizing it would launder an undefined score into an exchange measurement.\")","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierNikeFuel/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNikeFuel","unit":"count","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.intentionally-unsupported-source-type","error":"intentionallyUnsupported(GroveHealthKitFHIR.HealthKitSourceType.nikeFuel, reason: \"NikeFuel is an opaque vendor index with an unpublished formula and a retired ecosystem; it has no physiological dimension, no UCUM representation beyond an arbitrary annotation, and no second source, so normalizing it would launder an undefined score into an exchange measurement.\")","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierNikeFuel/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNikeFuel","unit":"count","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.intentionally-unsupported-source-type","error":"intentionallyUnsupported(GroveHealthKitFHIR.HealthKitSourceType.nikeFuel, reason: \"NikeFuel is an opaque vendor index with an unpublished formula and a retired ecosystem; it has no physiological dimension, no UCUM representation beyond an arbitrary annotation, and no second source, so normalizing it would launder an undefined score into an exchange measurement.\")","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierNikeFuel/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNikeFuel","unit":"count","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.intentionally-unsupported-source-type","error":"intentionallyUnsupported(GroveHealthKitFHIR.HealthKitSourceType.nikeFuel, reason: \"NikeFuel is an opaque vendor index with an unpublished formula and a retired ecosystem; it has no physiological dimension, no UCUM representation beyond an arbitrary annotation, and no second source, so normalizing it would launder an undefined score into an exchange measurement.\")","location":"HKSample.sampleType"}}} +{"id":"quantity/HKQuantityTypeIdentifierNumberOfAlcoholicBeverages/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNumberOfAlcoholicBeverages","unit":"count","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"number-of-alcoholic-beverages","display":"Number of alcoholic beverages","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierNumberOfAlcoholicBeverages"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:RUPmGYWgvLF-eVWuXuyPJNKVBppUc59fduz4ceOwcS4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yUCp265qNeZmimOneHqY2ozqKmz8tz4R_-EunvCwf0M"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-number-of-alcoholic-beverages"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{drinks}","system":"http://unitsofmeasure.org","unit":"drinks","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierNumberOfAlcoholicBeverages/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNumberOfAlcoholicBeverages","unit":"count","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"number-of-alcoholic-beverages","display":"Number of alcoholic beverages","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierNumberOfAlcoholicBeverages"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:RUPmGYWgvLF-eVWuXuyPJNKVBppUc59fduz4ceOwcS4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yUCp265qNeZmimOneHqY2ozqKmz8tz4R_-EunvCwf0M"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-number-of-alcoholic-beverages"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{drinks}","system":"http://unitsofmeasure.org","unit":"drinks","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierNumberOfAlcoholicBeverages/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNumberOfAlcoholicBeverages","unit":"count","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.numberOfAlcoholicBeverages, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierNumberOfAlcoholicBeverages/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNumberOfAlcoholicBeverages","unit":"count","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.numberOfAlcoholicBeverages, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierNumberOfAlcoholicBeverages/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNumberOfAlcoholicBeverages","unit":"count","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.numberOfAlcoholicBeverages, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierNumberOfAlcoholicBeverages/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNumberOfAlcoholicBeverages","unit":"count","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"number-of-alcoholic-beverages","display":"Number of alcoholic beverages","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierNumberOfAlcoholicBeverages"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:RUPmGYWgvLF-eVWuXuyPJNKVBppUc59fduz4ceOwcS4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yUCp265qNeZmimOneHqY2ozqKmz8tz4R_-EunvCwf0M"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-number-of-alcoholic-beverages"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{drinks}","system":"http://unitsofmeasure.org","unit":"drinks","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierNumberOfAlcoholicBeverages/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNumberOfAlcoholicBeverages","unit":"count","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.numberOfAlcoholicBeverages, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierNumberOfAlcoholicBeverages/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNumberOfAlcoholicBeverages","unit":"count","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.numberOfAlcoholicBeverages, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierNumberOfAlcoholicBeverages/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNumberOfAlcoholicBeverages","unit":"count","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.numberOfAlcoholicBeverages, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierNumberOfTimesFallen/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNumberOfTimesFallen","unit":"count","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"number-of-times-fallen","display":"Number of times fallen","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierNumberOfTimesFallen"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:L_HVK6Y_didLcYgEYp9XYf-w5DTlrzrY1hFHgVZd4-k"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3v3iPsOhW0rnb7m4sZnF6uo6TytkQrhV8BVYpFzEX-E"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-number-of-times-fallen"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{falls}","system":"http://unitsofmeasure.org","unit":"falls","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierNumberOfTimesFallen/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNumberOfTimesFallen","unit":"count","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"number-of-times-fallen","display":"Number of times fallen","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierNumberOfTimesFallen"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:L_HVK6Y_didLcYgEYp9XYf-w5DTlrzrY1hFHgVZd4-k"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3v3iPsOhW0rnb7m4sZnF6uo6TytkQrhV8BVYpFzEX-E"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-number-of-times-fallen"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{falls}","system":"http://unitsofmeasure.org","unit":"falls","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierNumberOfTimesFallen/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNumberOfTimesFallen","unit":"count","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.numberOfTimesFallen, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierNumberOfTimesFallen/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNumberOfTimesFallen","unit":"count","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.numberOfTimesFallen, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierNumberOfTimesFallen/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNumberOfTimesFallen","unit":"count","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.numberOfTimesFallen, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierNumberOfTimesFallen/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNumberOfTimesFallen","unit":"count","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"number-of-times-fallen","display":"Number of times fallen","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierNumberOfTimesFallen"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:L_HVK6Y_didLcYgEYp9XYf-w5DTlrzrY1hFHgVZd4-k"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3v3iPsOhW0rnb7m4sZnF6uo6TytkQrhV8BVYpFzEX-E"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-number-of-times-fallen"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{falls}","system":"http://unitsofmeasure.org","unit":"falls","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierNumberOfTimesFallen/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNumberOfTimesFallen","unit":"count","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.numberOfTimesFallen, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierNumberOfTimesFallen/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNumberOfTimesFallen","unit":"count","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.numberOfTimesFallen, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierNumberOfTimesFallen/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierNumberOfTimesFallen","unit":"count","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.numberOfTimesFallen, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierOxygenSaturation/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierOxygenSaturation","unit":"%","value":0.25}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"2708-6","display":"Oxygen saturation in Arterial blood","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierOxygenSaturation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xB9JtwL2KBygfb_ByezBr0CGq_tA4SL4SmrQqyw0wYc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kJCLgxjnjVCiRnxoQ-t-oaLe4EbL5jv1W2arIvGpfqg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-oxygen-saturation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":25}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierOxygenSaturation/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierOxygenSaturation","unit":"%","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"2708-6","display":"Oxygen saturation in Arterial blood","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierOxygenSaturation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xB9JtwL2KBygfb_ByezBr0CGq_tA4SL4SmrQqyw0wYc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kJCLgxjnjVCiRnxoQ-t-oaLe4EbL5jv1W2arIvGpfqg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-oxygen-saturation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierOxygenSaturation/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierOxygenSaturation","unit":"%","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.oxygenSaturation, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierOxygenSaturation/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierOxygenSaturation","unit":"%","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.oxygenSaturation, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierOxygenSaturation/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierOxygenSaturation","unit":"%","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"2708-6","display":"Oxygen saturation in Arterial blood","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierOxygenSaturation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xB9JtwL2KBygfb_ByezBr0CGq_tA4SL4SmrQqyw0wYc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kJCLgxjnjVCiRnxoQ-t-oaLe4EbL5jv1W2arIvGpfqg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-oxygen-saturation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":0.000009999999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierOxygenSaturation/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierOxygenSaturation","unit":"%","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.oxygenSaturation, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierOxygenSaturation/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierOxygenSaturation","unit":"%","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.oxygenSaturation, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierOxygenSaturation/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierOxygenSaturation","unit":"%","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.oxygenSaturation, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierOxygenSaturation/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierOxygenSaturation","unit":"%","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.oxygenSaturation, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierOxygenSaturation/fraction-0.07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierOxygenSaturation","unit":"%","value":0.07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"2708-6","display":"Oxygen saturation in Arterial blood","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierOxygenSaturation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xB9JtwL2KBygfb_ByezBr0CGq_tA4SL4SmrQqyw0wYc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kJCLgxjnjVCiRnxoQ-t-oaLe4EbL5jv1W2arIvGpfqg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-oxygen-saturation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":7.000000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierOxygenSaturation/fraction-0.14","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierOxygenSaturation","unit":"%","value":0.14}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"2708-6","display":"Oxygen saturation in Arterial blood","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierOxygenSaturation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xB9JtwL2KBygfb_ByezBr0CGq_tA4SL4SmrQqyw0wYc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kJCLgxjnjVCiRnxoQ-t-oaLe4EbL5jv1W2arIvGpfqg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-oxygen-saturation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":14.000000000000002}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierOxygenSaturation/fraction-0.28","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierOxygenSaturation","unit":"%","value":0.28}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"2708-6","display":"Oxygen saturation in Arterial blood","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierOxygenSaturation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xB9JtwL2KBygfb_ByezBr0CGq_tA4SL4SmrQqyw0wYc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kJCLgxjnjVCiRnxoQ-t-oaLe4EbL5jv1W2arIvGpfqg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-oxygen-saturation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.000000000000004}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierOxygenSaturation/fraction-0.282","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierOxygenSaturation","unit":"%","value":0.282}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"2708-6","display":"Oxygen saturation in Arterial blood","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierOxygenSaturation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xB9JtwL2KBygfb_ByezBr0CGq_tA4SL4SmrQqyw0wYc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kJCLgxjnjVCiRnxoQ-t-oaLe4EbL5jv1W2arIvGpfqg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-oxygen-saturation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.199999999999996}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierOxygenSaturation/fraction-0.29","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierOxygenSaturation","unit":"%","value":0.29}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"2708-6","display":"Oxygen saturation in Arterial blood","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierOxygenSaturation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xB9JtwL2KBygfb_ByezBr0CGq_tA4SL4SmrQqyw0wYc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kJCLgxjnjVCiRnxoQ-t-oaLe4EbL5jv1W2arIvGpfqg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-oxygen-saturation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.999999999999996}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierOxygenSaturation/fraction-0.55","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierOxygenSaturation","unit":"%","value":0.55}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"2708-6","display":"Oxygen saturation in Arterial blood","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierOxygenSaturation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xB9JtwL2KBygfb_ByezBr0CGq_tA4SL4SmrQqyw0wYc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kJCLgxjnjVCiRnxoQ-t-oaLe4EbL5jv1W2arIvGpfqg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-oxygen-saturation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":55.00000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierOxygenSaturation/fraction-0.56","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierOxygenSaturation","unit":"%","value":0.56}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"2708-6","display":"Oxygen saturation in Arterial blood","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierOxygenSaturation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xB9JtwL2KBygfb_ByezBr0CGq_tA4SL4SmrQqyw0wYc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kJCLgxjnjVCiRnxoQ-t-oaLe4EbL5jv1W2arIvGpfqg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-oxygen-saturation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":56.00000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierOxygenSaturation/fraction-0.57","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierOxygenSaturation","unit":"%","value":0.57}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"2708-6","display":"Oxygen saturation in Arterial blood","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierOxygenSaturation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xB9JtwL2KBygfb_ByezBr0CGq_tA4SL4SmrQqyw0wYc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kJCLgxjnjVCiRnxoQ-t-oaLe4EbL5jv1W2arIvGpfqg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-oxygen-saturation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":56.99999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierOxygenSaturation/fraction-0.58","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierOxygenSaturation","unit":"%","value":0.58}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"2708-6","display":"Oxygen saturation in Arterial blood","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierOxygenSaturation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xB9JtwL2KBygfb_ByezBr0CGq_tA4SL4SmrQqyw0wYc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kJCLgxjnjVCiRnxoQ-t-oaLe4EbL5jv1W2arIvGpfqg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-oxygen-saturation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":57.99999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierOxygenSaturation/fraction-0.98","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierOxygenSaturation","unit":"%","value":0.98}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"2708-6","display":"Oxygen saturation in Arterial blood","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierOxygenSaturation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xB9JtwL2KBygfb_ByezBr0CGq_tA4SL4SmrQqyw0wYc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kJCLgxjnjVCiRnxoQ-t-oaLe4EbL5jv1W2arIvGpfqg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-oxygen-saturation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":98}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierOxygenSaturation/fraction-0.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierOxygenSaturation","unit":"%","value":0.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"2708-6","display":"Oxygen saturation in Arterial blood","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierOxygenSaturation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xB9JtwL2KBygfb_ByezBr0CGq_tA4SL4SmrQqyw0wYc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kJCLgxjnjVCiRnxoQ-t-oaLe4EbL5jv1W2arIvGpfqg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-oxygen-saturation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":50}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierOxygenSaturation/fraction-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierOxygenSaturation","unit":"%","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"2708-6","display":"Oxygen saturation in Arterial blood","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierOxygenSaturation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xB9JtwL2KBygfb_ByezBr0CGq_tA4SL4SmrQqyw0wYc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kJCLgxjnjVCiRnxoQ-t-oaLe4EbL5jv1W2arIvGpfqg"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-oxygen-saturation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":100}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPaddleSportsSpeed/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPaddleSportsSpeed","unit":"m/s","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPaddleSportsSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yBQx6XTkNhF6jVUOK_1zn0dxJOKRSJNdFGFRPyQ6dWc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vaj2mA6HpVsR4YR2JIT7Lozj17xq7Vqxxqh4YCdiGao"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPaddleSportsSpeed/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPaddleSportsSpeed","unit":"m/s","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPaddleSportsSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yBQx6XTkNhF6jVUOK_1zn0dxJOKRSJNdFGFRPyQ6dWc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vaj2mA6HpVsR4YR2JIT7Lozj17xq7Vqxxqh4YCdiGao"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPaddleSportsSpeed/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPaddleSportsSpeed","unit":"m/s","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPaddleSportsSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yBQx6XTkNhF6jVUOK_1zn0dxJOKRSJNdFGFRPyQ6dWc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vaj2mA6HpVsR4YR2JIT7Lozj17xq7Vqxxqh4YCdiGao"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPaddleSportsSpeed/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPaddleSportsSpeed","unit":"m/s","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPaddleSportsSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yBQx6XTkNhF6jVUOK_1zn0dxJOKRSJNdFGFRPyQ6dWc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vaj2mA6HpVsR4YR2JIT7Lozj17xq7Vqxxqh4YCdiGao"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPaddleSportsSpeed/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPaddleSportsSpeed","unit":"m/s","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPaddleSportsSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yBQx6XTkNhF6jVUOK_1zn0dxJOKRSJNdFGFRPyQ6dWc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vaj2mA6HpVsR4YR2JIT7Lozj17xq7Vqxxqh4YCdiGao"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPaddleSportsSpeed/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPaddleSportsSpeed","unit":"m/s","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPaddleSportsSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yBQx6XTkNhF6jVUOK_1zn0dxJOKRSJNdFGFRPyQ6dWc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vaj2mA6HpVsR4YR2JIT7Lozj17xq7Vqxxqh4YCdiGao"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPaddleSportsSpeed/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPaddleSportsSpeed","unit":"m/s","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.paddleSportsSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierPaddleSportsSpeed/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPaddleSportsSpeed","unit":"m/s","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.paddleSportsSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierPaddleSportsSpeed/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPaddleSportsSpeed","unit":"m/s","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.paddleSportsSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierPeakExpiratoryFlowRate/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeakExpiratoryFlowRate","unit":"L/min","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"33452-4","display":"Maximum expiratory gas flow Respiratory system airway","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPeakExpiratoryFlowRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gKxD4GrLsnYA91kzvju-0aA0Sfv4FHnEuDpGvHI6J0w"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MFz_6XL-EE1lL1CLrRZUf1DCUYmjbLIywBl_xwucdu4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-peak-expiratory-flow-rate"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"L/min","system":"http://unitsofmeasure.org","unit":"L/min","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPeakExpiratoryFlowRate/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeakExpiratoryFlowRate","unit":"L/min","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"33452-4","display":"Maximum expiratory gas flow Respiratory system airway","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPeakExpiratoryFlowRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gKxD4GrLsnYA91kzvju-0aA0Sfv4FHnEuDpGvHI6J0w"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MFz_6XL-EE1lL1CLrRZUf1DCUYmjbLIywBl_xwucdu4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-peak-expiratory-flow-rate"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"L/min","system":"http://unitsofmeasure.org","unit":"L/min","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPeakExpiratoryFlowRate/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeakExpiratoryFlowRate","unit":"L/min","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"33452-4","display":"Maximum expiratory gas flow Respiratory system airway","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPeakExpiratoryFlowRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gKxD4GrLsnYA91kzvju-0aA0Sfv4FHnEuDpGvHI6J0w"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MFz_6XL-EE1lL1CLrRZUf1DCUYmjbLIywBl_xwucdu4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-peak-expiratory-flow-rate"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"L/min","system":"http://unitsofmeasure.org","unit":"L/min","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPeakExpiratoryFlowRate/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeakExpiratoryFlowRate","unit":"L/min","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"33452-4","display":"Maximum expiratory gas flow Respiratory system airway","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPeakExpiratoryFlowRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gKxD4GrLsnYA91kzvju-0aA0Sfv4FHnEuDpGvHI6J0w"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MFz_6XL-EE1lL1CLrRZUf1DCUYmjbLIywBl_xwucdu4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-peak-expiratory-flow-rate"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"L/min","system":"http://unitsofmeasure.org","unit":"L/min","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPeakExpiratoryFlowRate/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeakExpiratoryFlowRate","unit":"L/min","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"33452-4","display":"Maximum expiratory gas flow Respiratory system airway","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPeakExpiratoryFlowRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gKxD4GrLsnYA91kzvju-0aA0Sfv4FHnEuDpGvHI6J0w"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MFz_6XL-EE1lL1CLrRZUf1DCUYmjbLIywBl_xwucdu4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-peak-expiratory-flow-rate"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"L/min","system":"http://unitsofmeasure.org","unit":"L/min","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPeakExpiratoryFlowRate/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeakExpiratoryFlowRate","unit":"L/min","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"33452-4","display":"Maximum expiratory gas flow Respiratory system airway","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPeakExpiratoryFlowRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:gKxD4GrLsnYA91kzvju-0aA0Sfv4FHnEuDpGvHI6J0w"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MFz_6XL-EE1lL1CLrRZUf1DCUYmjbLIywBl_xwucdu4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-peak-expiratory-flow-rate"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"L/min","system":"http://unitsofmeasure.org","unit":"L/min","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPeakExpiratoryFlowRate/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeakExpiratoryFlowRate","unit":"L/min","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.peakExpiratoryFlowRate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierPeakExpiratoryFlowRate/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeakExpiratoryFlowRate","unit":"L/min","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.peakExpiratoryFlowRate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierPeakExpiratoryFlowRate/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeakExpiratoryFlowRate","unit":"L/min","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.peakExpiratoryFlowRate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierPeripheralPerfusionIndex/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeripheralPerfusionIndex","unit":"%","value":0.25}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"61006-3","display":"Perfusion index Tissue by Pulse oximetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPeripheralPerfusionIndex"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_E4XXWWncRXmg780CyRh77uTkckZnMC-sF-pgccFbTU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E81tjjITJPZKemUVUiHvNwcdGvME1XZgV8UwZFq8sKw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-peripheral-perfusion-index"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":25}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPeripheralPerfusionIndex/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeripheralPerfusionIndex","unit":"%","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"61006-3","display":"Perfusion index Tissue by Pulse oximetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPeripheralPerfusionIndex"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_E4XXWWncRXmg780CyRh77uTkckZnMC-sF-pgccFbTU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E81tjjITJPZKemUVUiHvNwcdGvME1XZgV8UwZFq8sKw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-peripheral-perfusion-index"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPeripheralPerfusionIndex/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeripheralPerfusionIndex","unit":"%","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.peripheralPerfusionIndex, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierPeripheralPerfusionIndex/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeripheralPerfusionIndex","unit":"%","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.peripheralPerfusionIndex, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierPeripheralPerfusionIndex/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeripheralPerfusionIndex","unit":"%","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"61006-3","display":"Perfusion index Tissue by Pulse oximetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPeripheralPerfusionIndex"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_E4XXWWncRXmg780CyRh77uTkckZnMC-sF-pgccFbTU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E81tjjITJPZKemUVUiHvNwcdGvME1XZgV8UwZFq8sKw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-peripheral-perfusion-index"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":0.000009999999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPeripheralPerfusionIndex/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeripheralPerfusionIndex","unit":"%","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.peripheralPerfusionIndex, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierPeripheralPerfusionIndex/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeripheralPerfusionIndex","unit":"%","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.peripheralPerfusionIndex, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierPeripheralPerfusionIndex/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeripheralPerfusionIndex","unit":"%","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.peripheralPerfusionIndex, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierPeripheralPerfusionIndex/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeripheralPerfusionIndex","unit":"%","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.peripheralPerfusionIndex, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierPeripheralPerfusionIndex/fraction-0.07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeripheralPerfusionIndex","unit":"%","value":0.07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"61006-3","display":"Perfusion index Tissue by Pulse oximetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPeripheralPerfusionIndex"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_E4XXWWncRXmg780CyRh77uTkckZnMC-sF-pgccFbTU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E81tjjITJPZKemUVUiHvNwcdGvME1XZgV8UwZFq8sKw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-peripheral-perfusion-index"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":7.000000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPeripheralPerfusionIndex/fraction-0.14","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeripheralPerfusionIndex","unit":"%","value":0.14}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"61006-3","display":"Perfusion index Tissue by Pulse oximetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPeripheralPerfusionIndex"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_E4XXWWncRXmg780CyRh77uTkckZnMC-sF-pgccFbTU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E81tjjITJPZKemUVUiHvNwcdGvME1XZgV8UwZFq8sKw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-peripheral-perfusion-index"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":14.000000000000002}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPeripheralPerfusionIndex/fraction-0.28","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeripheralPerfusionIndex","unit":"%","value":0.28}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"61006-3","display":"Perfusion index Tissue by Pulse oximetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPeripheralPerfusionIndex"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_E4XXWWncRXmg780CyRh77uTkckZnMC-sF-pgccFbTU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E81tjjITJPZKemUVUiHvNwcdGvME1XZgV8UwZFq8sKw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-peripheral-perfusion-index"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.000000000000004}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPeripheralPerfusionIndex/fraction-0.282","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeripheralPerfusionIndex","unit":"%","value":0.282}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"61006-3","display":"Perfusion index Tissue by Pulse oximetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPeripheralPerfusionIndex"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_E4XXWWncRXmg780CyRh77uTkckZnMC-sF-pgccFbTU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E81tjjITJPZKemUVUiHvNwcdGvME1XZgV8UwZFq8sKw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-peripheral-perfusion-index"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.199999999999996}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPeripheralPerfusionIndex/fraction-0.29","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeripheralPerfusionIndex","unit":"%","value":0.29}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"61006-3","display":"Perfusion index Tissue by Pulse oximetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPeripheralPerfusionIndex"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_E4XXWWncRXmg780CyRh77uTkckZnMC-sF-pgccFbTU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E81tjjITJPZKemUVUiHvNwcdGvME1XZgV8UwZFq8sKw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-peripheral-perfusion-index"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.999999999999996}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPeripheralPerfusionIndex/fraction-0.55","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeripheralPerfusionIndex","unit":"%","value":0.55}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"61006-3","display":"Perfusion index Tissue by Pulse oximetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPeripheralPerfusionIndex"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_E4XXWWncRXmg780CyRh77uTkckZnMC-sF-pgccFbTU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E81tjjITJPZKemUVUiHvNwcdGvME1XZgV8UwZFq8sKw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-peripheral-perfusion-index"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":55.00000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPeripheralPerfusionIndex/fraction-0.56","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeripheralPerfusionIndex","unit":"%","value":0.56}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"61006-3","display":"Perfusion index Tissue by Pulse oximetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPeripheralPerfusionIndex"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_E4XXWWncRXmg780CyRh77uTkckZnMC-sF-pgccFbTU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E81tjjITJPZKemUVUiHvNwcdGvME1XZgV8UwZFq8sKw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-peripheral-perfusion-index"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":56.00000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPeripheralPerfusionIndex/fraction-0.57","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeripheralPerfusionIndex","unit":"%","value":0.57}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"61006-3","display":"Perfusion index Tissue by Pulse oximetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPeripheralPerfusionIndex"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_E4XXWWncRXmg780CyRh77uTkckZnMC-sF-pgccFbTU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E81tjjITJPZKemUVUiHvNwcdGvME1XZgV8UwZFq8sKw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-peripheral-perfusion-index"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":56.99999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPeripheralPerfusionIndex/fraction-0.58","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeripheralPerfusionIndex","unit":"%","value":0.58}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"61006-3","display":"Perfusion index Tissue by Pulse oximetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPeripheralPerfusionIndex"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_E4XXWWncRXmg780CyRh77uTkckZnMC-sF-pgccFbTU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E81tjjITJPZKemUVUiHvNwcdGvME1XZgV8UwZFq8sKw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-peripheral-perfusion-index"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":57.99999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPeripheralPerfusionIndex/fraction-0.98","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeripheralPerfusionIndex","unit":"%","value":0.98}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"61006-3","display":"Perfusion index Tissue by Pulse oximetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPeripheralPerfusionIndex"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_E4XXWWncRXmg780CyRh77uTkckZnMC-sF-pgccFbTU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E81tjjITJPZKemUVUiHvNwcdGvME1XZgV8UwZFq8sKw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-peripheral-perfusion-index"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":98}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPeripheralPerfusionIndex/fraction-0.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeripheralPerfusionIndex","unit":"%","value":0.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"61006-3","display":"Perfusion index Tissue by Pulse oximetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPeripheralPerfusionIndex"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_E4XXWWncRXmg780CyRh77uTkckZnMC-sF-pgccFbTU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E81tjjITJPZKemUVUiHvNwcdGvME1XZgV8UwZFq8sKw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-peripheral-perfusion-index"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":50}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPeripheralPerfusionIndex/fraction-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPeripheralPerfusionIndex","unit":"%","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"61006-3","display":"Perfusion index Tissue by Pulse oximetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPeripheralPerfusionIndex"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_E4XXWWncRXmg780CyRh77uTkckZnMC-sF-pgccFbTU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E81tjjITJPZKemUVUiHvNwcdGvME1XZgV8UwZFq8sKw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-peripheral-perfusion-index"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":100}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPhysicalEffort/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPhysicalEffort","unit":"kcal/hr·kg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"physical-effort","display":"Physical effort","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPhysicalEffort"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xvlppW1ZTjCVRn4P_499NIolDPwpSnVECFUEZz_Y7JM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:H0I-Bs2QyAQo_tGWalRzJq1fWyYDclSyHBPLOXAMzL4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-physical-effort"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal/kg/h","system":"http://unitsofmeasure.org","unit":"kcal/(kg.h)","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPhysicalEffort/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPhysicalEffort","unit":"kcal/hr·kg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"physical-effort","display":"Physical effort","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPhysicalEffort"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xvlppW1ZTjCVRn4P_499NIolDPwpSnVECFUEZz_Y7JM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:H0I-Bs2QyAQo_tGWalRzJq1fWyYDclSyHBPLOXAMzL4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-physical-effort"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal/kg/h","system":"http://unitsofmeasure.org","unit":"kcal/(kg.h)","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPhysicalEffort/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPhysicalEffort","unit":"kcal/hr·kg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"physical-effort","display":"Physical effort","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPhysicalEffort"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xvlppW1ZTjCVRn4P_499NIolDPwpSnVECFUEZz_Y7JM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:H0I-Bs2QyAQo_tGWalRzJq1fWyYDclSyHBPLOXAMzL4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-physical-effort"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal/kg/h","system":"http://unitsofmeasure.org","unit":"kcal/(kg.h)","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPhysicalEffort/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPhysicalEffort","unit":"kcal/hr·kg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"physical-effort","display":"Physical effort","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPhysicalEffort"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xvlppW1ZTjCVRn4P_499NIolDPwpSnVECFUEZz_Y7JM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:H0I-Bs2QyAQo_tGWalRzJq1fWyYDclSyHBPLOXAMzL4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-physical-effort"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal/kg/h","system":"http://unitsofmeasure.org","unit":"kcal/(kg.h)","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPhysicalEffort/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPhysicalEffort","unit":"kcal/hr·kg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"physical-effort","display":"Physical effort","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPhysicalEffort"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xvlppW1ZTjCVRn4P_499NIolDPwpSnVECFUEZz_Y7JM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:H0I-Bs2QyAQo_tGWalRzJq1fWyYDclSyHBPLOXAMzL4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-physical-effort"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal/kg/h","system":"http://unitsofmeasure.org","unit":"kcal/(kg.h)","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPhysicalEffort/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPhysicalEffort","unit":"kcal/hr·kg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"physical-effort","display":"Physical effort","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPhysicalEffort"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xvlppW1ZTjCVRn4P_499NIolDPwpSnVECFUEZz_Y7JM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:H0I-Bs2QyAQo_tGWalRzJq1fWyYDclSyHBPLOXAMzL4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-physical-effort"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal/kg/h","system":"http://unitsofmeasure.org","unit":"kcal/(kg.h)","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPhysicalEffort/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPhysicalEffort","unit":"kcal/hr·kg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.physicalEffort, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierPhysicalEffort/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPhysicalEffort","unit":"kcal/hr·kg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.physicalEffort, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierPhysicalEffort/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPhysicalEffort","unit":"kcal/hr·kg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.physicalEffort, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierPushCount/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPushCount","unit":"count","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"96502-0","display":"Number of wheelchair pushes per time period","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPushCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:76R5eqgBJ_GaGTz24rrvCNwriwncNzPpKXYunxMvkwI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:swWRsHJ7ht_4a63-drWvaw0hyqZoeKlzp3RXfrnK5GI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-wheelchair-push-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{pushes}","system":"http://unitsofmeasure.org","unit":"pushes","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPushCount/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPushCount","unit":"count","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"96502-0","display":"Number of wheelchair pushes per time period","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPushCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:76R5eqgBJ_GaGTz24rrvCNwriwncNzPpKXYunxMvkwI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:swWRsHJ7ht_4a63-drWvaw0hyqZoeKlzp3RXfrnK5GI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-wheelchair-push-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{pushes}","system":"http://unitsofmeasure.org","unit":"pushes","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPushCount/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPushCount","unit":"count","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pushCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierPushCount/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPushCount","unit":"count","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pushCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierPushCount/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPushCount","unit":"count","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pushCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierPushCount/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPushCount","unit":"count","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"96502-0","display":"Number of wheelchair pushes per time period","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierPushCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:76R5eqgBJ_GaGTz24rrvCNwriwncNzPpKXYunxMvkwI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:swWRsHJ7ht_4a63-drWvaw0hyqZoeKlzp3RXfrnK5GI"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-wheelchair-push-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{pushes}","system":"http://unitsofmeasure.org","unit":"pushes","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierPushCount/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPushCount","unit":"count","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pushCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierPushCount/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPushCount","unit":"count","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pushCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierPushCount/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierPushCount","unit":"count","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pushCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRespiratoryRate/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRespiratoryRate","unit":"count/min","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"9279-1","display":"Respiratory rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRespiratoryRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ybjG2TOqpE-m0yDXJbfz0_dBbgwT2yd1rIxntxQSotQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PjWL9E0MWw1xJZaMvqQGLYUcytnBQgZGAWJMWCBeyK0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-respiratory-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"breaths/minute","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRespiratoryRate/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRespiratoryRate","unit":"count/min","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"9279-1","display":"Respiratory rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRespiratoryRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ybjG2TOqpE-m0yDXJbfz0_dBbgwT2yd1rIxntxQSotQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PjWL9E0MWw1xJZaMvqQGLYUcytnBQgZGAWJMWCBeyK0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-respiratory-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"breaths/minute","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRespiratoryRate/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRespiratoryRate","unit":"count/min","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"9279-1","display":"Respiratory rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRespiratoryRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ybjG2TOqpE-m0yDXJbfz0_dBbgwT2yd1rIxntxQSotQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PjWL9E0MWw1xJZaMvqQGLYUcytnBQgZGAWJMWCBeyK0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-respiratory-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"breaths/minute","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRespiratoryRate/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRespiratoryRate","unit":"count/min","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"9279-1","display":"Respiratory rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRespiratoryRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ybjG2TOqpE-m0yDXJbfz0_dBbgwT2yd1rIxntxQSotQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PjWL9E0MWw1xJZaMvqQGLYUcytnBQgZGAWJMWCBeyK0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-respiratory-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"breaths/minute","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRespiratoryRate/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRespiratoryRate","unit":"count/min","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"9279-1","display":"Respiratory rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRespiratoryRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ybjG2TOqpE-m0yDXJbfz0_dBbgwT2yd1rIxntxQSotQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PjWL9E0MWw1xJZaMvqQGLYUcytnBQgZGAWJMWCBeyK0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-respiratory-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"breaths/minute","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRespiratoryRate/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRespiratoryRate","unit":"count/min","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"9279-1","display":"Respiratory rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRespiratoryRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ybjG2TOqpE-m0yDXJbfz0_dBbgwT2yd1rIxntxQSotQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PjWL9E0MWw1xJZaMvqQGLYUcytnBQgZGAWJMWCBeyK0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-respiratory-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"breaths/minute","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRespiratoryRate/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRespiratoryRate","unit":"count/min","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.respiratoryRate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRespiratoryRate/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRespiratoryRate","unit":"count/min","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.respiratoryRate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRespiratoryRate/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRespiratoryRate","unit":"count/min","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.respiratoryRate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRestingHeartRate/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRestingHeartRate","unit":"count/min","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"40443-4","display":"Heart rate --resting","system":"http://loinc.org"},{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRestingHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:rtfCymcBaq5b1R_s6NA0lnOkM3P8C9nCHALkPPutsWw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yIG4-aaiZHaveNWCsHPy6nKOw1abRtjpbfduLI4gzac"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-resting-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRestingHeartRate/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRestingHeartRate","unit":"count/min","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"40443-4","display":"Heart rate --resting","system":"http://loinc.org"},{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRestingHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:rtfCymcBaq5b1R_s6NA0lnOkM3P8C9nCHALkPPutsWw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yIG4-aaiZHaveNWCsHPy6nKOw1abRtjpbfduLI4gzac"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-resting-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRestingHeartRate/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRestingHeartRate","unit":"count/min","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"40443-4","display":"Heart rate --resting","system":"http://loinc.org"},{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRestingHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:rtfCymcBaq5b1R_s6NA0lnOkM3P8C9nCHALkPPutsWw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yIG4-aaiZHaveNWCsHPy6nKOw1abRtjpbfduLI4gzac"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-resting-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRestingHeartRate/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRestingHeartRate","unit":"count/min","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"40443-4","display":"Heart rate --resting","system":"http://loinc.org"},{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRestingHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:rtfCymcBaq5b1R_s6NA0lnOkM3P8C9nCHALkPPutsWw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yIG4-aaiZHaveNWCsHPy6nKOw1abRtjpbfduLI4gzac"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-resting-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRestingHeartRate/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRestingHeartRate","unit":"count/min","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"40443-4","display":"Heart rate --resting","system":"http://loinc.org"},{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRestingHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:rtfCymcBaq5b1R_s6NA0lnOkM3P8C9nCHALkPPutsWw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yIG4-aaiZHaveNWCsHPy6nKOw1abRtjpbfduLI4gzac"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-resting-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRestingHeartRate/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRestingHeartRate","unit":"count/min","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"40443-4","display":"Heart rate --resting","system":"http://loinc.org"},{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRestingHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:rtfCymcBaq5b1R_s6NA0lnOkM3P8C9nCHALkPPutsWw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yIG4-aaiZHaveNWCsHPy6nKOw1abRtjpbfduLI4gzac"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-resting-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRestingHeartRate/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRestingHeartRate","unit":"count/min","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.restingHeartRate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRestingHeartRate/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRestingHeartRate","unit":"count/min","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.restingHeartRate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRestingHeartRate/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRestingHeartRate","unit":"count/min","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.restingHeartRate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRowingSpeed/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRowingSpeed","unit":"m/s","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRowingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dp60Vg8H7sqGxHNtgdxoNfG9jcY_hnByEPEFq2jJ2zE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fr-87LJxn0rvQ3KBRCtO-dDUS4yVuCp7B36wW1hAbAU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRowingSpeed/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRowingSpeed","unit":"m/s","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRowingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dp60Vg8H7sqGxHNtgdxoNfG9jcY_hnByEPEFq2jJ2zE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fr-87LJxn0rvQ3KBRCtO-dDUS4yVuCp7B36wW1hAbAU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRowingSpeed/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRowingSpeed","unit":"m/s","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRowingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dp60Vg8H7sqGxHNtgdxoNfG9jcY_hnByEPEFq2jJ2zE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fr-87LJxn0rvQ3KBRCtO-dDUS4yVuCp7B36wW1hAbAU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRowingSpeed/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRowingSpeed","unit":"m/s","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRowingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dp60Vg8H7sqGxHNtgdxoNfG9jcY_hnByEPEFq2jJ2zE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fr-87LJxn0rvQ3KBRCtO-dDUS4yVuCp7B36wW1hAbAU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRowingSpeed/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRowingSpeed","unit":"m/s","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRowingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dp60Vg8H7sqGxHNtgdxoNfG9jcY_hnByEPEFq2jJ2zE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fr-87LJxn0rvQ3KBRCtO-dDUS4yVuCp7B36wW1hAbAU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRowingSpeed/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRowingSpeed","unit":"m/s","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRowingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dp60Vg8H7sqGxHNtgdxoNfG9jcY_hnByEPEFq2jJ2zE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fr-87LJxn0rvQ3KBRCtO-dDUS4yVuCp7B36wW1hAbAU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRowingSpeed/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRowingSpeed","unit":"m/s","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.rowingSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRowingSpeed/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRowingSpeed","unit":"m/s","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.rowingSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRowingSpeed/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRowingSpeed","unit":"m/s","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.rowingSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRunningGroundContactTime/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningGroundContactTime","unit":"ms","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"running-ground-contact-time","display":"Running ground contact time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningGroundContactTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2q6Tr7iUbftw_nMKgbtfr96swiOTz75C1Olyl4LBYvY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:aLDDHZD-WZAqW8b17N3NnlX-fJHh1ZW6W4tLzBjZHeo"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-running-ground-contact-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ms","system":"http://unitsofmeasure.org","unit":"ms","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningGroundContactTime/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningGroundContactTime","unit":"ms","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"running-ground-contact-time","display":"Running ground contact time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningGroundContactTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2q6Tr7iUbftw_nMKgbtfr96swiOTz75C1Olyl4LBYvY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:aLDDHZD-WZAqW8b17N3NnlX-fJHh1ZW6W4tLzBjZHeo"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-running-ground-contact-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ms","system":"http://unitsofmeasure.org","unit":"ms","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningGroundContactTime/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningGroundContactTime","unit":"ms","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"running-ground-contact-time","display":"Running ground contact time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningGroundContactTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2q6Tr7iUbftw_nMKgbtfr96swiOTz75C1Olyl4LBYvY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:aLDDHZD-WZAqW8b17N3NnlX-fJHh1ZW6W4tLzBjZHeo"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-running-ground-contact-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ms","system":"http://unitsofmeasure.org","unit":"ms","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningGroundContactTime/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningGroundContactTime","unit":"ms","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"running-ground-contact-time","display":"Running ground contact time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningGroundContactTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2q6Tr7iUbftw_nMKgbtfr96swiOTz75C1Olyl4LBYvY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:aLDDHZD-WZAqW8b17N3NnlX-fJHh1ZW6W4tLzBjZHeo"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-running-ground-contact-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ms","system":"http://unitsofmeasure.org","unit":"ms","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningGroundContactTime/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningGroundContactTime","unit":"ms","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"running-ground-contact-time","display":"Running ground contact time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningGroundContactTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2q6Tr7iUbftw_nMKgbtfr96swiOTz75C1Olyl4LBYvY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:aLDDHZD-WZAqW8b17N3NnlX-fJHh1ZW6W4tLzBjZHeo"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-running-ground-contact-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ms","system":"http://unitsofmeasure.org","unit":"ms","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningGroundContactTime/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningGroundContactTime","unit":"ms","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"running-ground-contact-time","display":"Running ground contact time","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningGroundContactTime"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2q6Tr7iUbftw_nMKgbtfr96swiOTz75C1Olyl4LBYvY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:aLDDHZD-WZAqW8b17N3NnlX-fJHh1ZW6W4tLzBjZHeo"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-running-ground-contact-time"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"ms","system":"http://unitsofmeasure.org","unit":"ms","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningGroundContactTime/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningGroundContactTime","unit":"ms","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.runningGroundContactTime, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRunningGroundContactTime/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningGroundContactTime","unit":"ms","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.runningGroundContactTime, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRunningGroundContactTime/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningGroundContactTime","unit":"ms","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.runningGroundContactTime, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRunningPower/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningPower","unit":"W","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"power","display":"Power","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningPower"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YWo2aSFuHP6p8b4fFVsaCDkkGhr6gb3T2vbEgysnjJw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VAEA7XXS-6OcrVq_ZyQlb0hzDTli7PnyCggiZ6YJXEA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-power","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"W","system":"http://unitsofmeasure.org","unit":"W","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningPower/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningPower","unit":"W","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"power","display":"Power","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningPower"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YWo2aSFuHP6p8b4fFVsaCDkkGhr6gb3T2vbEgysnjJw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VAEA7XXS-6OcrVq_ZyQlb0hzDTli7PnyCggiZ6YJXEA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-power","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"W","system":"http://unitsofmeasure.org","unit":"W","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningPower/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningPower","unit":"W","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"power","display":"Power","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningPower"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YWo2aSFuHP6p8b4fFVsaCDkkGhr6gb3T2vbEgysnjJw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VAEA7XXS-6OcrVq_ZyQlb0hzDTli7PnyCggiZ6YJXEA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-power","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"W","system":"http://unitsofmeasure.org","unit":"W","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningPower/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningPower","unit":"W","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"power","display":"Power","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningPower"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YWo2aSFuHP6p8b4fFVsaCDkkGhr6gb3T2vbEgysnjJw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VAEA7XXS-6OcrVq_ZyQlb0hzDTli7PnyCggiZ6YJXEA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-power","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"W","system":"http://unitsofmeasure.org","unit":"W","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningPower/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningPower","unit":"W","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"power","display":"Power","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningPower"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YWo2aSFuHP6p8b4fFVsaCDkkGhr6gb3T2vbEgysnjJw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VAEA7XXS-6OcrVq_ZyQlb0hzDTli7PnyCggiZ6YJXEA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-power","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"W","system":"http://unitsofmeasure.org","unit":"W","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningPower/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningPower","unit":"W","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"power","display":"Power","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningPower"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YWo2aSFuHP6p8b4fFVsaCDkkGhr6gb3T2vbEgysnjJw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VAEA7XXS-6OcrVq_ZyQlb0hzDTli7PnyCggiZ6YJXEA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-power","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"W","system":"http://unitsofmeasure.org","unit":"W","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningPower/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningPower","unit":"W","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.runningPower, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRunningPower/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningPower","unit":"W","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.runningPower, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRunningPower/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningPower","unit":"W","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.runningPower, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRunningSpeed/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningSpeed","unit":"m/s","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:XWVLNzbWvc_n0qBZMEkhCn0u2Tw0PXZJjD8uxWudIVg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jMxky9gFzof5e4-C-r7rzq1c0TTXGayR2ICw9mdHuQA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningSpeed/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningSpeed","unit":"m/s","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:XWVLNzbWvc_n0qBZMEkhCn0u2Tw0PXZJjD8uxWudIVg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jMxky9gFzof5e4-C-r7rzq1c0TTXGayR2ICw9mdHuQA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningSpeed/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningSpeed","unit":"m/s","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:XWVLNzbWvc_n0qBZMEkhCn0u2Tw0PXZJjD8uxWudIVg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jMxky9gFzof5e4-C-r7rzq1c0TTXGayR2ICw9mdHuQA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningSpeed/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningSpeed","unit":"m/s","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:XWVLNzbWvc_n0qBZMEkhCn0u2Tw0PXZJjD8uxWudIVg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jMxky9gFzof5e4-C-r7rzq1c0TTXGayR2ICw9mdHuQA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningSpeed/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningSpeed","unit":"m/s","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:XWVLNzbWvc_n0qBZMEkhCn0u2Tw0PXZJjD8uxWudIVg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jMxky9gFzof5e4-C-r7rzq1c0TTXGayR2ICw9mdHuQA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningSpeed/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningSpeed","unit":"m/s","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"speed","display":"Speed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:XWVLNzbWvc_n0qBZMEkhCn0u2Tw0PXZJjD8uxWudIVg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jMxky9gFzof5e4-C-r7rzq1c0TTXGayR2ICw9mdHuQA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningSpeed/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningSpeed","unit":"m/s","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.runningSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRunningSpeed/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningSpeed","unit":"m/s","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.runningSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRunningSpeed/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningSpeed","unit":"m/s","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.runningSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRunningStrideLength/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningStrideLength","unit":"m","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"running-stride-length","display":"Running stride length","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningStrideLength"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:oisiZ4uTBLPsRo059gVOz4vlCx4SslKTDLFK91_6l1M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BG9v9m_TIn55hL3Cc0O9zboK-sySIu1an18H0dMhnn4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-running-stride-length"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningStrideLength/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningStrideLength","unit":"m","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"running-stride-length","display":"Running stride length","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningStrideLength"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:oisiZ4uTBLPsRo059gVOz4vlCx4SslKTDLFK91_6l1M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BG9v9m_TIn55hL3Cc0O9zboK-sySIu1an18H0dMhnn4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-running-stride-length"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningStrideLength/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningStrideLength","unit":"m","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"running-stride-length","display":"Running stride length","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningStrideLength"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:oisiZ4uTBLPsRo059gVOz4vlCx4SslKTDLFK91_6l1M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BG9v9m_TIn55hL3Cc0O9zboK-sySIu1an18H0dMhnn4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-running-stride-length"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningStrideLength/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningStrideLength","unit":"m","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"running-stride-length","display":"Running stride length","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningStrideLength"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:oisiZ4uTBLPsRo059gVOz4vlCx4SslKTDLFK91_6l1M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BG9v9m_TIn55hL3Cc0O9zboK-sySIu1an18H0dMhnn4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-running-stride-length"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningStrideLength/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningStrideLength","unit":"m","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"running-stride-length","display":"Running stride length","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningStrideLength"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:oisiZ4uTBLPsRo059gVOz4vlCx4SslKTDLFK91_6l1M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BG9v9m_TIn55hL3Cc0O9zboK-sySIu1an18H0dMhnn4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-running-stride-length"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningStrideLength/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningStrideLength","unit":"m","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"running-stride-length","display":"Running stride length","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningStrideLength"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:oisiZ4uTBLPsRo059gVOz4vlCx4SslKTDLFK91_6l1M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BG9v9m_TIn55hL3Cc0O9zboK-sySIu1an18H0dMhnn4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-running-stride-length"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningStrideLength/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningStrideLength","unit":"m","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.runningStrideLength, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRunningStrideLength/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningStrideLength","unit":"m","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.runningStrideLength, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRunningStrideLength/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningStrideLength","unit":"m","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.runningStrideLength, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRunningVerticalOscillation/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningVerticalOscillation","unit":"cm","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"running-vertical-oscillation","display":"Running vertical oscillation","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningVerticalOscillation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:a_hEv09rFkkXZHYJNT9WHjmp_MfhZqlbW7Tr6o-16sw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:mDAluKnXGNjE-UeyKHSBhX9KopcrCWQZZlHld5B1vsg"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-running-vertical-oscillation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningVerticalOscillation/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningVerticalOscillation","unit":"cm","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"running-vertical-oscillation","display":"Running vertical oscillation","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningVerticalOscillation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:a_hEv09rFkkXZHYJNT9WHjmp_MfhZqlbW7Tr6o-16sw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:mDAluKnXGNjE-UeyKHSBhX9KopcrCWQZZlHld5B1vsg"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-running-vertical-oscillation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningVerticalOscillation/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningVerticalOscillation","unit":"cm","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"running-vertical-oscillation","display":"Running vertical oscillation","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningVerticalOscillation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:a_hEv09rFkkXZHYJNT9WHjmp_MfhZqlbW7Tr6o-16sw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:mDAluKnXGNjE-UeyKHSBhX9KopcrCWQZZlHld5B1vsg"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-running-vertical-oscillation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningVerticalOscillation/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningVerticalOscillation","unit":"cm","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"running-vertical-oscillation","display":"Running vertical oscillation","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningVerticalOscillation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:a_hEv09rFkkXZHYJNT9WHjmp_MfhZqlbW7Tr6o-16sw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:mDAluKnXGNjE-UeyKHSBhX9KopcrCWQZZlHld5B1vsg"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-running-vertical-oscillation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningVerticalOscillation/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningVerticalOscillation","unit":"cm","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"running-vertical-oscillation","display":"Running vertical oscillation","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningVerticalOscillation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:a_hEv09rFkkXZHYJNT9WHjmp_MfhZqlbW7Tr6o-16sw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:mDAluKnXGNjE-UeyKHSBhX9KopcrCWQZZlHld5B1vsg"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-running-vertical-oscillation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningVerticalOscillation/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningVerticalOscillation","unit":"cm","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"running-vertical-oscillation","display":"Running vertical oscillation","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierRunningVerticalOscillation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:a_hEv09rFkkXZHYJNT9WHjmp_MfhZqlbW7Tr6o-16sw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:mDAluKnXGNjE-UeyKHSBhX9KopcrCWQZZlHld5B1vsg"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-running-vertical-oscillation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierRunningVerticalOscillation/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningVerticalOscillation","unit":"cm","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.runningVerticalOscillation, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRunningVerticalOscillation/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningVerticalOscillation","unit":"cm","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.runningVerticalOscillation, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierRunningVerticalOscillation/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierRunningVerticalOscillation","unit":"cm","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.runningVerticalOscillation, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierSixMinuteWalkTestDistance/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierSixMinuteWalkTestDistance","unit":"m","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"64098-7","display":"Six minute walk test","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierSixMinuteWalkTestDistance"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ewWe3kFMeeV1i16UVLekavtFgvumDuZcS5zXnWXL6I4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:b0Zr1a_bf5kTxKR1cftBkW06JUkTDa0V31Nrl-GcuQE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-six-minute-walk-test-distance"]},"method":{"coding":[{"code":"rolling-mean","display":"Rolling mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierSixMinuteWalkTestDistance/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierSixMinuteWalkTestDistance","unit":"m","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"64098-7","display":"Six minute walk test","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierSixMinuteWalkTestDistance"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ewWe3kFMeeV1i16UVLekavtFgvumDuZcS5zXnWXL6I4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:b0Zr1a_bf5kTxKR1cftBkW06JUkTDa0V31Nrl-GcuQE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-six-minute-walk-test-distance"]},"method":{"coding":[{"code":"rolling-mean","display":"Rolling mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierSixMinuteWalkTestDistance/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierSixMinuteWalkTestDistance","unit":"m","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"64098-7","display":"Six minute walk test","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierSixMinuteWalkTestDistance"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ewWe3kFMeeV1i16UVLekavtFgvumDuZcS5zXnWXL6I4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:b0Zr1a_bf5kTxKR1cftBkW06JUkTDa0V31Nrl-GcuQE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-six-minute-walk-test-distance"]},"method":{"coding":[{"code":"rolling-mean","display":"Rolling mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierSixMinuteWalkTestDistance/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierSixMinuteWalkTestDistance","unit":"m","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"64098-7","display":"Six minute walk test","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierSixMinuteWalkTestDistance"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ewWe3kFMeeV1i16UVLekavtFgvumDuZcS5zXnWXL6I4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:b0Zr1a_bf5kTxKR1cftBkW06JUkTDa0V31Nrl-GcuQE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-six-minute-walk-test-distance"]},"method":{"coding":[{"code":"rolling-mean","display":"Rolling mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierSixMinuteWalkTestDistance/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierSixMinuteWalkTestDistance","unit":"m","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"64098-7","display":"Six minute walk test","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierSixMinuteWalkTestDistance"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ewWe3kFMeeV1i16UVLekavtFgvumDuZcS5zXnWXL6I4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:b0Zr1a_bf5kTxKR1cftBkW06JUkTDa0V31Nrl-GcuQE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-six-minute-walk-test-distance"]},"method":{"coding":[{"code":"rolling-mean","display":"Rolling mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierSixMinuteWalkTestDistance/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierSixMinuteWalkTestDistance","unit":"m","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"64098-7","display":"Six minute walk test","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierSixMinuteWalkTestDistance"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ewWe3kFMeeV1i16UVLekavtFgvumDuZcS5zXnWXL6I4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:b0Zr1a_bf5kTxKR1cftBkW06JUkTDa0V31Nrl-GcuQE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-six-minute-walk-test-distance"]},"method":{"coding":[{"code":"rolling-mean","display":"Rolling mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierSixMinuteWalkTestDistance/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierSixMinuteWalkTestDistance","unit":"m","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sixMinuteWalkTestDistance, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierSixMinuteWalkTestDistance/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierSixMinuteWalkTestDistance","unit":"m","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sixMinuteWalkTestDistance, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierSixMinuteWalkTestDistance/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierSixMinuteWalkTestDistance","unit":"m","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sixMinuteWalkTestDistance, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierStairAscentSpeed/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStairAscentSpeed","unit":"m/s","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112431-2","display":"Stair ascent speed [Velocity]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStairAscentSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:uaEe-qJMUiuAN-usa10JyV0dnD-WLLs4hGpvOdK0L9w"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:j3Wa5MwXLzftbjdhyb7KPnTfeThb4VLhvyJAYlXK19I"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-stair-ascent-speed"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierStairAscentSpeed/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStairAscentSpeed","unit":"m/s","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112431-2","display":"Stair ascent speed [Velocity]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStairAscentSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:uaEe-qJMUiuAN-usa10JyV0dnD-WLLs4hGpvOdK0L9w"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:j3Wa5MwXLzftbjdhyb7KPnTfeThb4VLhvyJAYlXK19I"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-stair-ascent-speed"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierStairAscentSpeed/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStairAscentSpeed","unit":"m/s","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112431-2","display":"Stair ascent speed [Velocity]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStairAscentSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:uaEe-qJMUiuAN-usa10JyV0dnD-WLLs4hGpvOdK0L9w"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:j3Wa5MwXLzftbjdhyb7KPnTfeThb4VLhvyJAYlXK19I"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-stair-ascent-speed"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierStairAscentSpeed/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStairAscentSpeed","unit":"m/s","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112431-2","display":"Stair ascent speed [Velocity]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStairAscentSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:uaEe-qJMUiuAN-usa10JyV0dnD-WLLs4hGpvOdK0L9w"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:j3Wa5MwXLzftbjdhyb7KPnTfeThb4VLhvyJAYlXK19I"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-stair-ascent-speed"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierStairAscentSpeed/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStairAscentSpeed","unit":"m/s","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112431-2","display":"Stair ascent speed [Velocity]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStairAscentSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:uaEe-qJMUiuAN-usa10JyV0dnD-WLLs4hGpvOdK0L9w"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:j3Wa5MwXLzftbjdhyb7KPnTfeThb4VLhvyJAYlXK19I"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-stair-ascent-speed"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierStairAscentSpeed/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStairAscentSpeed","unit":"m/s","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112431-2","display":"Stair ascent speed [Velocity]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStairAscentSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:uaEe-qJMUiuAN-usa10JyV0dnD-WLLs4hGpvOdK0L9w"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:j3Wa5MwXLzftbjdhyb7KPnTfeThb4VLhvyJAYlXK19I"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-stair-ascent-speed"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierStairAscentSpeed/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStairAscentSpeed","unit":"m/s","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stairAscentSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierStairAscentSpeed/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStairAscentSpeed","unit":"m/s","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stairAscentSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierStairAscentSpeed/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStairAscentSpeed","unit":"m/s","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stairAscentSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierStairDescentSpeed/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStairDescentSpeed","unit":"m/s","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112430-4","display":"Stair descent speed [Velocity]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStairDescentSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:R_sZjz9VkJ6peQ-X34KwdnIrIihK7nTENI-w95Vtujg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Ct2b7rYVJwUEp_-8g5WJ5LFsqG2hNkxHjTy8HxHO8FY"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-stair-descent-speed"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierStairDescentSpeed/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStairDescentSpeed","unit":"m/s","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112430-4","display":"Stair descent speed [Velocity]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStairDescentSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:R_sZjz9VkJ6peQ-X34KwdnIrIihK7nTENI-w95Vtujg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Ct2b7rYVJwUEp_-8g5WJ5LFsqG2hNkxHjTy8HxHO8FY"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-stair-descent-speed"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierStairDescentSpeed/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStairDescentSpeed","unit":"m/s","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112430-4","display":"Stair descent speed [Velocity]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStairDescentSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:R_sZjz9VkJ6peQ-X34KwdnIrIihK7nTENI-w95Vtujg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Ct2b7rYVJwUEp_-8g5WJ5LFsqG2hNkxHjTy8HxHO8FY"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-stair-descent-speed"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierStairDescentSpeed/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStairDescentSpeed","unit":"m/s","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112430-4","display":"Stair descent speed [Velocity]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStairDescentSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:R_sZjz9VkJ6peQ-X34KwdnIrIihK7nTENI-w95Vtujg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Ct2b7rYVJwUEp_-8g5WJ5LFsqG2hNkxHjTy8HxHO8FY"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-stair-descent-speed"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierStairDescentSpeed/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStairDescentSpeed","unit":"m/s","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112430-4","display":"Stair descent speed [Velocity]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStairDescentSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:R_sZjz9VkJ6peQ-X34KwdnIrIihK7nTENI-w95Vtujg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Ct2b7rYVJwUEp_-8g5WJ5LFsqG2hNkxHjTy8HxHO8FY"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-stair-descent-speed"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierStairDescentSpeed/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStairDescentSpeed","unit":"m/s","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112430-4","display":"Stair descent speed [Velocity]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStairDescentSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:R_sZjz9VkJ6peQ-X34KwdnIrIihK7nTENI-w95Vtujg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Ct2b7rYVJwUEp_-8g5WJ5LFsqG2hNkxHjTy8HxHO8FY"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-stair-descent-speed"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierStairDescentSpeed/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStairDescentSpeed","unit":"m/s","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stairDescentSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierStairDescentSpeed/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStairDescentSpeed","unit":"m/s","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stairDescentSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierStairDescentSpeed/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStairDescentSpeed","unit":"m/s","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stairDescentSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierStepCount/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierStepCount/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierStepCount/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stepCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierStepCount/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stepCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierStepCount/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stepCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierStepCount/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierStepCount/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stepCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierStepCount/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stepCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierStepCount/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stepCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierSwimmingStrokeCount/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierSwimmingStrokeCount","unit":"count","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"swimming-stroke-count","display":"Swimming stroke count","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierSwimmingStrokeCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:6z3a0OiYBnAa1hrdCeKtHBEv-7HPyKxFteSwHxdWSXA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:13o7szyMMM9vvPUPC3P3axoyzQN9c9l-YdK3QQdVaEI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-swimming-stroke-count"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{strokes}","system":"http://unitsofmeasure.org","unit":"strokes","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierSwimmingStrokeCount/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierSwimmingStrokeCount","unit":"count","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"swimming-stroke-count","display":"Swimming stroke count","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierSwimmingStrokeCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:6z3a0OiYBnAa1hrdCeKtHBEv-7HPyKxFteSwHxdWSXA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:13o7szyMMM9vvPUPC3P3axoyzQN9c9l-YdK3QQdVaEI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-swimming-stroke-count"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{strokes}","system":"http://unitsofmeasure.org","unit":"strokes","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierSwimmingStrokeCount/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierSwimmingStrokeCount","unit":"count","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.swimmingStrokeCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierSwimmingStrokeCount/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierSwimmingStrokeCount","unit":"count","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.swimmingStrokeCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierSwimmingStrokeCount/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierSwimmingStrokeCount","unit":"count","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.swimmingStrokeCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierSwimmingStrokeCount/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierSwimmingStrokeCount","unit":"count","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"swimming-stroke-count","display":"Swimming stroke count","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierSwimmingStrokeCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:6z3a0OiYBnAa1hrdCeKtHBEv-7HPyKxFteSwHxdWSXA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:13o7szyMMM9vvPUPC3P3axoyzQN9c9l-YdK3QQdVaEI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-swimming-stroke-count"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{strokes}","system":"http://unitsofmeasure.org","unit":"strokes","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierSwimmingStrokeCount/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierSwimmingStrokeCount","unit":"count","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.swimmingStrokeCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierSwimmingStrokeCount/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierSwimmingStrokeCount","unit":"count","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.swimmingStrokeCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierSwimmingStrokeCount/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierSwimmingStrokeCount","unit":"count","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.swimmingStrokeCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierTimeInDaylight/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierTimeInDaylight","unit":"min","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"time-in-daylight","display":"Time in daylight","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierTimeInDaylight"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:p4R8KlO25Gmb8UoQqk48l5FXbD_IKO17uPmwXxhVwo0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:owHWmojP88feTmVli2oQoFgzAS7YKBFXY14v5u4TtnU"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-time-in-daylight"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierTimeInDaylight/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierTimeInDaylight","unit":"min","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"time-in-daylight","display":"Time in daylight","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierTimeInDaylight"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:p4R8KlO25Gmb8UoQqk48l5FXbD_IKO17uPmwXxhVwo0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:owHWmojP88feTmVli2oQoFgzAS7YKBFXY14v5u4TtnU"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-time-in-daylight"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierTimeInDaylight/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierTimeInDaylight","unit":"min","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"time-in-daylight","display":"Time in daylight","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierTimeInDaylight"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:p4R8KlO25Gmb8UoQqk48l5FXbD_IKO17uPmwXxhVwo0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:owHWmojP88feTmVli2oQoFgzAS7YKBFXY14v5u4TtnU"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-time-in-daylight"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierTimeInDaylight/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierTimeInDaylight","unit":"min","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"time-in-daylight","display":"Time in daylight","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierTimeInDaylight"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:p4R8KlO25Gmb8UoQqk48l5FXbD_IKO17uPmwXxhVwo0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:owHWmojP88feTmVli2oQoFgzAS7YKBFXY14v5u4TtnU"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-time-in-daylight"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierTimeInDaylight/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierTimeInDaylight","unit":"min","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"time-in-daylight","display":"Time in daylight","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierTimeInDaylight"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:p4R8KlO25Gmb8UoQqk48l5FXbD_IKO17uPmwXxhVwo0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:owHWmojP88feTmVli2oQoFgzAS7YKBFXY14v5u4TtnU"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-time-in-daylight"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierTimeInDaylight/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierTimeInDaylight","unit":"min","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"time-in-daylight","display":"Time in daylight","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierTimeInDaylight"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:p4R8KlO25Gmb8UoQqk48l5FXbD_IKO17uPmwXxhVwo0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:owHWmojP88feTmVli2oQoFgzAS7YKBFXY14v5u4TtnU"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-time-in-daylight"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierTimeInDaylight/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierTimeInDaylight","unit":"min","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.timeInDaylight, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierTimeInDaylight/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierTimeInDaylight","unit":"min","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.timeInDaylight, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierTimeInDaylight/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierTimeInDaylight","unit":"min","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.timeInDaylight, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierUVExposure/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierUVExposure","unit":"count","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"uv-exposure","display":"UV exposure","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierUVExposure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:cWEX9_8ySR8egK41l4aRZi-Q9SdSESdwS4hXE6ZvNeE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:TEPGgDIb0vLvWeC0tSHLPHz9O6-mgr0ZQUsK8rugzI4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-uv-exposure"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{uvindex}","system":"http://unitsofmeasure.org","unit":"UV index","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierUVExposure/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierUVExposure","unit":"count","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"uv-exposure","display":"UV exposure","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierUVExposure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:cWEX9_8ySR8egK41l4aRZi-Q9SdSESdwS4hXE6ZvNeE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:TEPGgDIb0vLvWeC0tSHLPHz9O6-mgr0ZQUsK8rugzI4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-uv-exposure"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{uvindex}","system":"http://unitsofmeasure.org","unit":"UV index","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierUVExposure/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierUVExposure","unit":"count","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"uv-exposure","display":"UV exposure","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierUVExposure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:cWEX9_8ySR8egK41l4aRZi-Q9SdSESdwS4hXE6ZvNeE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:TEPGgDIb0vLvWeC0tSHLPHz9O6-mgr0ZQUsK8rugzI4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-uv-exposure"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{uvindex}","system":"http://unitsofmeasure.org","unit":"UV index","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierUVExposure/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierUVExposure","unit":"count","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"uv-exposure","display":"UV exposure","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierUVExposure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:cWEX9_8ySR8egK41l4aRZi-Q9SdSESdwS4hXE6ZvNeE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:TEPGgDIb0vLvWeC0tSHLPHz9O6-mgr0ZQUsK8rugzI4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-uv-exposure"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{uvindex}","system":"http://unitsofmeasure.org","unit":"UV index","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierUVExposure/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierUVExposure","unit":"count","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"uv-exposure","display":"UV exposure","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierUVExposure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:cWEX9_8ySR8egK41l4aRZi-Q9SdSESdwS4hXE6ZvNeE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:TEPGgDIb0vLvWeC0tSHLPHz9O6-mgr0ZQUsK8rugzI4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-uv-exposure"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{uvindex}","system":"http://unitsofmeasure.org","unit":"UV index","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierUVExposure/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierUVExposure","unit":"count","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"uv-exposure","display":"UV exposure","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierUVExposure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:cWEX9_8ySR8egK41l4aRZi-Q9SdSESdwS4hXE6ZvNeE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:TEPGgDIb0vLvWeC0tSHLPHz9O6-mgr0ZQUsK8rugzI4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-uv-exposure"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{uvindex}","system":"http://unitsofmeasure.org","unit":"UV index","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierUVExposure/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierUVExposure","unit":"count","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.uvExposure, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierUVExposure/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierUVExposure","unit":"count","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.uvExposure, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierUVExposure/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierUVExposure","unit":"count","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.uvExposure, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierUnderwaterDepth/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierUnderwaterDepth","unit":"m","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"underwater-depth","display":"Underwater depth","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierUnderwaterDepth"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:9pfz3ybYcaY-NEu9U2VtGWC2sduV0k0_l7J7Cz7MoFU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v1aG_LqrJPbgU1bUbHmaeqcr69zm7-SCMfxfrlSlOUI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-underwater-depth"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierUnderwaterDepth/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierUnderwaterDepth","unit":"m","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"underwater-depth","display":"Underwater depth","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierUnderwaterDepth"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:9pfz3ybYcaY-NEu9U2VtGWC2sduV0k0_l7J7Cz7MoFU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v1aG_LqrJPbgU1bUbHmaeqcr69zm7-SCMfxfrlSlOUI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-underwater-depth"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierUnderwaterDepth/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierUnderwaterDepth","unit":"m","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"underwater-depth","display":"Underwater depth","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierUnderwaterDepth"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:9pfz3ybYcaY-NEu9U2VtGWC2sduV0k0_l7J7Cz7MoFU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v1aG_LqrJPbgU1bUbHmaeqcr69zm7-SCMfxfrlSlOUI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-underwater-depth"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierUnderwaterDepth/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierUnderwaterDepth","unit":"m","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"underwater-depth","display":"Underwater depth","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierUnderwaterDepth"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:9pfz3ybYcaY-NEu9U2VtGWC2sduV0k0_l7J7Cz7MoFU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v1aG_LqrJPbgU1bUbHmaeqcr69zm7-SCMfxfrlSlOUI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-underwater-depth"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierUnderwaterDepth/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierUnderwaterDepth","unit":"m","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"underwater-depth","display":"Underwater depth","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierUnderwaterDepth"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:9pfz3ybYcaY-NEu9U2VtGWC2sduV0k0_l7J7Cz7MoFU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v1aG_LqrJPbgU1bUbHmaeqcr69zm7-SCMfxfrlSlOUI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-underwater-depth"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierUnderwaterDepth/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierUnderwaterDepth","unit":"m","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"underwater-depth","display":"Underwater depth","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierUnderwaterDepth"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:9pfz3ybYcaY-NEu9U2VtGWC2sduV0k0_l7J7Cz7MoFU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v1aG_LqrJPbgU1bUbHmaeqcr69zm7-SCMfxfrlSlOUI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-underwater-depth"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierUnderwaterDepth/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierUnderwaterDepth","unit":"m","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.underwaterDepth, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierUnderwaterDepth/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierUnderwaterDepth","unit":"m","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.underwaterDepth, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierUnderwaterDepth/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierUnderwaterDepth","unit":"m","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.underwaterDepth, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierVO2Max/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierVO2Max","unit":"mL/min·kg","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"vo2-max","display":"VO2 max","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierVO2Max"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4gN_cHa2h_w_2Dhqa6YDKi6Yw2Fd92sGMAq0e3-Qex0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5TLbUVCfMr0CTfA6ZepwWHAWClohZ-F_l9mlCdmN2jA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-vo2-max","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mL/kg/min","system":"http://unitsofmeasure.org","unit":"mL/kg/min","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierVO2Max/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierVO2Max","unit":"mL/min·kg","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"vo2-max","display":"VO2 max","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierVO2Max"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4gN_cHa2h_w_2Dhqa6YDKi6Yw2Fd92sGMAq0e3-Qex0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5TLbUVCfMr0CTfA6ZepwWHAWClohZ-F_l9mlCdmN2jA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-vo2-max","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mL/kg/min","system":"http://unitsofmeasure.org","unit":"mL/kg/min","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierVO2Max/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierVO2Max","unit":"mL/min·kg","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"vo2-max","display":"VO2 max","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierVO2Max"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4gN_cHa2h_w_2Dhqa6YDKi6Yw2Fd92sGMAq0e3-Qex0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5TLbUVCfMr0CTfA6ZepwWHAWClohZ-F_l9mlCdmN2jA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-vo2-max","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mL/kg/min","system":"http://unitsofmeasure.org","unit":"mL/kg/min","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierVO2Max/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierVO2Max","unit":"mL/min·kg","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"vo2-max","display":"VO2 max","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierVO2Max"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4gN_cHa2h_w_2Dhqa6YDKi6Yw2Fd92sGMAq0e3-Qex0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5TLbUVCfMr0CTfA6ZepwWHAWClohZ-F_l9mlCdmN2jA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-vo2-max","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mL/kg/min","system":"http://unitsofmeasure.org","unit":"mL/kg/min","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierVO2Max/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierVO2Max","unit":"mL/min·kg","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"vo2-max","display":"VO2 max","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierVO2Max"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4gN_cHa2h_w_2Dhqa6YDKi6Yw2Fd92sGMAq0e3-Qex0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5TLbUVCfMr0CTfA6ZepwWHAWClohZ-F_l9mlCdmN2jA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-vo2-max","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mL/kg/min","system":"http://unitsofmeasure.org","unit":"mL/kg/min","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierVO2Max/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierVO2Max","unit":"mL/min·kg","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"vo2-max","display":"VO2 max","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierVO2Max"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4gN_cHa2h_w_2Dhqa6YDKi6Yw2Fd92sGMAq0e3-Qex0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5TLbUVCfMr0CTfA6ZepwWHAWClohZ-F_l9mlCdmN2jA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-vo2-max","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"mL/kg/min","system":"http://unitsofmeasure.org","unit":"mL/kg/min","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierVO2Max/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierVO2Max","unit":"mL/min·kg","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.vo2Max, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierVO2Max/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierVO2Max","unit":"mL/min·kg","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.vo2Max, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierVO2Max/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierVO2Max","unit":"mL/min·kg","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.vo2Max, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWaistCircumference/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWaistCircumference","unit":"cm","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"8280-0","display":"Waist Circumference at umbilicus by Tape measure","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWaistCircumference"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fhGnAe-1R_ym-bNBYekpx8jcqu5Wm6OulNZbPNRPeVk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:IZVkqWtpVky4Kma4vKktj0f7mR4VsmII-0slWPA5Yzc"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-waist-circumference"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWaistCircumference/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWaistCircumference","unit":"cm","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"8280-0","display":"Waist Circumference at umbilicus by Tape measure","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWaistCircumference"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fhGnAe-1R_ym-bNBYekpx8jcqu5Wm6OulNZbPNRPeVk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:IZVkqWtpVky4Kma4vKktj0f7mR4VsmII-0slWPA5Yzc"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-waist-circumference"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWaistCircumference/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWaistCircumference","unit":"cm","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"8280-0","display":"Waist Circumference at umbilicus by Tape measure","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWaistCircumference"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fhGnAe-1R_ym-bNBYekpx8jcqu5Wm6OulNZbPNRPeVk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:IZVkqWtpVky4Kma4vKktj0f7mR4VsmII-0slWPA5Yzc"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-waist-circumference"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWaistCircumference/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWaistCircumference","unit":"cm","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"8280-0","display":"Waist Circumference at umbilicus by Tape measure","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWaistCircumference"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fhGnAe-1R_ym-bNBYekpx8jcqu5Wm6OulNZbPNRPeVk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:IZVkqWtpVky4Kma4vKktj0f7mR4VsmII-0slWPA5Yzc"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-waist-circumference"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWaistCircumference/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWaistCircumference","unit":"cm","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"8280-0","display":"Waist Circumference at umbilicus by Tape measure","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWaistCircumference"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fhGnAe-1R_ym-bNBYekpx8jcqu5Wm6OulNZbPNRPeVk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:IZVkqWtpVky4Kma4vKktj0f7mR4VsmII-0slWPA5Yzc"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-waist-circumference"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWaistCircumference/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWaistCircumference","unit":"cm","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"8280-0","display":"Waist Circumference at umbilicus by Tape measure","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWaistCircumference"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fhGnAe-1R_ym-bNBYekpx8jcqu5Wm6OulNZbPNRPeVk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:IZVkqWtpVky4Kma4vKktj0f7mR4VsmII-0slWPA5Yzc"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-waist-circumference"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWaistCircumference/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWaistCircumference","unit":"cm","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.waistCircumference, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWaistCircumference/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWaistCircumference","unit":"cm","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.waistCircumference, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWaistCircumference/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWaistCircumference","unit":"cm","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.waistCircumference, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingAsymmetryPercentage/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage","unit":"%","value":0.25}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112432-0","display":"Walking asymmetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0LFqx_zBa_mKQudeJSO5R0edT36PiYQ8IwQXZ3Hvudk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zuwR4uTrlDipCW8Ja2X81jaT4Qc-J85cqyGYnlmkjxQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-asymmetry"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":25}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingAsymmetryPercentage/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage","unit":"%","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112432-0","display":"Walking asymmetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0LFqx_zBa_mKQudeJSO5R0edT36PiYQ8IwQXZ3Hvudk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zuwR4uTrlDipCW8Ja2X81jaT4Qc-J85cqyGYnlmkjxQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-asymmetry"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingAsymmetryPercentage/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage","unit":"%","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.walkingAsymmetryPercentage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingAsymmetryPercentage/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage","unit":"%","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.walkingAsymmetryPercentage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingAsymmetryPercentage/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage","unit":"%","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112432-0","display":"Walking asymmetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0LFqx_zBa_mKQudeJSO5R0edT36PiYQ8IwQXZ3Hvudk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zuwR4uTrlDipCW8Ja2X81jaT4Qc-J85cqyGYnlmkjxQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-asymmetry"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":0.000009999999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingAsymmetryPercentage/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage","unit":"%","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.walkingAsymmetryPercentage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingAsymmetryPercentage/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage","unit":"%","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.walkingAsymmetryPercentage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingAsymmetryPercentage/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage","unit":"%","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.walkingAsymmetryPercentage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingAsymmetryPercentage/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage","unit":"%","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.walkingAsymmetryPercentage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingAsymmetryPercentage/fraction-0.07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage","unit":"%","value":0.07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112432-0","display":"Walking asymmetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0LFqx_zBa_mKQudeJSO5R0edT36PiYQ8IwQXZ3Hvudk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zuwR4uTrlDipCW8Ja2X81jaT4Qc-J85cqyGYnlmkjxQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-asymmetry"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":7.000000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingAsymmetryPercentage/fraction-0.14","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage","unit":"%","value":0.14}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112432-0","display":"Walking asymmetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0LFqx_zBa_mKQudeJSO5R0edT36PiYQ8IwQXZ3Hvudk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zuwR4uTrlDipCW8Ja2X81jaT4Qc-J85cqyGYnlmkjxQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-asymmetry"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":14.000000000000002}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingAsymmetryPercentage/fraction-0.28","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage","unit":"%","value":0.28}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112432-0","display":"Walking asymmetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0LFqx_zBa_mKQudeJSO5R0edT36PiYQ8IwQXZ3Hvudk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zuwR4uTrlDipCW8Ja2X81jaT4Qc-J85cqyGYnlmkjxQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-asymmetry"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.000000000000004}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingAsymmetryPercentage/fraction-0.282","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage","unit":"%","value":0.282}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112432-0","display":"Walking asymmetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0LFqx_zBa_mKQudeJSO5R0edT36PiYQ8IwQXZ3Hvudk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zuwR4uTrlDipCW8Ja2X81jaT4Qc-J85cqyGYnlmkjxQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-asymmetry"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.199999999999996}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingAsymmetryPercentage/fraction-0.29","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage","unit":"%","value":0.29}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112432-0","display":"Walking asymmetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0LFqx_zBa_mKQudeJSO5R0edT36PiYQ8IwQXZ3Hvudk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zuwR4uTrlDipCW8Ja2X81jaT4Qc-J85cqyGYnlmkjxQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-asymmetry"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.999999999999996}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingAsymmetryPercentage/fraction-0.55","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage","unit":"%","value":0.55}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112432-0","display":"Walking asymmetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0LFqx_zBa_mKQudeJSO5R0edT36PiYQ8IwQXZ3Hvudk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zuwR4uTrlDipCW8Ja2X81jaT4Qc-J85cqyGYnlmkjxQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-asymmetry"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":55.00000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingAsymmetryPercentage/fraction-0.56","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage","unit":"%","value":0.56}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112432-0","display":"Walking asymmetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0LFqx_zBa_mKQudeJSO5R0edT36PiYQ8IwQXZ3Hvudk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zuwR4uTrlDipCW8Ja2X81jaT4Qc-J85cqyGYnlmkjxQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-asymmetry"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":56.00000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingAsymmetryPercentage/fraction-0.57","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage","unit":"%","value":0.57}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112432-0","display":"Walking asymmetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0LFqx_zBa_mKQudeJSO5R0edT36PiYQ8IwQXZ3Hvudk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zuwR4uTrlDipCW8Ja2X81jaT4Qc-J85cqyGYnlmkjxQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-asymmetry"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":56.99999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingAsymmetryPercentage/fraction-0.58","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage","unit":"%","value":0.58}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112432-0","display":"Walking asymmetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0LFqx_zBa_mKQudeJSO5R0edT36PiYQ8IwQXZ3Hvudk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zuwR4uTrlDipCW8Ja2X81jaT4Qc-J85cqyGYnlmkjxQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-asymmetry"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":57.99999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingAsymmetryPercentage/fraction-0.98","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage","unit":"%","value":0.98}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112432-0","display":"Walking asymmetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0LFqx_zBa_mKQudeJSO5R0edT36PiYQ8IwQXZ3Hvudk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zuwR4uTrlDipCW8Ja2X81jaT4Qc-J85cqyGYnlmkjxQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-asymmetry"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":98}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingAsymmetryPercentage/fraction-0.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage","unit":"%","value":0.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112432-0","display":"Walking asymmetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0LFqx_zBa_mKQudeJSO5R0edT36PiYQ8IwQXZ3Hvudk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zuwR4uTrlDipCW8Ja2X81jaT4Qc-J85cqyGYnlmkjxQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-asymmetry"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":50}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingAsymmetryPercentage/fraction-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage","unit":"%","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112432-0","display":"Walking asymmetry","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0LFqx_zBa_mKQudeJSO5R0edT36PiYQ8IwQXZ3Hvudk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zuwR4uTrlDipCW8Ja2X81jaT4Qc-J85cqyGYnlmkjxQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-asymmetry"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":100}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingDoubleSupportPercentage/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage","unit":"%","value":0.25}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112434-6","display":"Walking double support [Percentile]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fZymmR4AUJOtr-j1qT76-4KdPVBAvRJViUGHok-7Izs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:flGK88mclfUqADwVs8LcLtZGFiJQpfZcieGreysp2RA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-double-support"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":25}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingDoubleSupportPercentage/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage","unit":"%","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112434-6","display":"Walking double support [Percentile]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fZymmR4AUJOtr-j1qT76-4KdPVBAvRJViUGHok-7Izs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:flGK88mclfUqADwVs8LcLtZGFiJQpfZcieGreysp2RA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-double-support"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingDoubleSupportPercentage/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage","unit":"%","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.walkingDoubleSupportPercentage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingDoubleSupportPercentage/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage","unit":"%","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.walkingDoubleSupportPercentage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingDoubleSupportPercentage/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage","unit":"%","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112434-6","display":"Walking double support [Percentile]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fZymmR4AUJOtr-j1qT76-4KdPVBAvRJViUGHok-7Izs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:flGK88mclfUqADwVs8LcLtZGFiJQpfZcieGreysp2RA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-double-support"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":0.000009999999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingDoubleSupportPercentage/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage","unit":"%","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.walkingDoubleSupportPercentage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingDoubleSupportPercentage/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage","unit":"%","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.walkingDoubleSupportPercentage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingDoubleSupportPercentage/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage","unit":"%","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.walkingDoubleSupportPercentage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingDoubleSupportPercentage/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage","unit":"%","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.walkingDoubleSupportPercentage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingDoubleSupportPercentage/fraction-0.07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage","unit":"%","value":0.07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112434-6","display":"Walking double support [Percentile]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fZymmR4AUJOtr-j1qT76-4KdPVBAvRJViUGHok-7Izs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:flGK88mclfUqADwVs8LcLtZGFiJQpfZcieGreysp2RA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-double-support"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":7.000000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingDoubleSupportPercentage/fraction-0.14","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage","unit":"%","value":0.14}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112434-6","display":"Walking double support [Percentile]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fZymmR4AUJOtr-j1qT76-4KdPVBAvRJViUGHok-7Izs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:flGK88mclfUqADwVs8LcLtZGFiJQpfZcieGreysp2RA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-double-support"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":14.000000000000002}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingDoubleSupportPercentage/fraction-0.28","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage","unit":"%","value":0.28}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112434-6","display":"Walking double support [Percentile]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fZymmR4AUJOtr-j1qT76-4KdPVBAvRJViUGHok-7Izs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:flGK88mclfUqADwVs8LcLtZGFiJQpfZcieGreysp2RA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-double-support"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.000000000000004}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingDoubleSupportPercentage/fraction-0.282","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage","unit":"%","value":0.282}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112434-6","display":"Walking double support [Percentile]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fZymmR4AUJOtr-j1qT76-4KdPVBAvRJViUGHok-7Izs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:flGK88mclfUqADwVs8LcLtZGFiJQpfZcieGreysp2RA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-double-support"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.199999999999996}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingDoubleSupportPercentage/fraction-0.29","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage","unit":"%","value":0.29}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112434-6","display":"Walking double support [Percentile]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fZymmR4AUJOtr-j1qT76-4KdPVBAvRJViUGHok-7Izs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:flGK88mclfUqADwVs8LcLtZGFiJQpfZcieGreysp2RA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-double-support"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":28.999999999999996}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingDoubleSupportPercentage/fraction-0.55","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage","unit":"%","value":0.55}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112434-6","display":"Walking double support [Percentile]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fZymmR4AUJOtr-j1qT76-4KdPVBAvRJViUGHok-7Izs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:flGK88mclfUqADwVs8LcLtZGFiJQpfZcieGreysp2RA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-double-support"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":55.00000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingDoubleSupportPercentage/fraction-0.56","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage","unit":"%","value":0.56}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112434-6","display":"Walking double support [Percentile]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fZymmR4AUJOtr-j1qT76-4KdPVBAvRJViUGHok-7Izs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:flGK88mclfUqADwVs8LcLtZGFiJQpfZcieGreysp2RA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-double-support"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":56.00000000000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingDoubleSupportPercentage/fraction-0.57","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage","unit":"%","value":0.57}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112434-6","display":"Walking double support [Percentile]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fZymmR4AUJOtr-j1qT76-4KdPVBAvRJViUGHok-7Izs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:flGK88mclfUqADwVs8LcLtZGFiJQpfZcieGreysp2RA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-double-support"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":56.99999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingDoubleSupportPercentage/fraction-0.58","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage","unit":"%","value":0.58}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112434-6","display":"Walking double support [Percentile]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fZymmR4AUJOtr-j1qT76-4KdPVBAvRJViUGHok-7Izs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:flGK88mclfUqADwVs8LcLtZGFiJQpfZcieGreysp2RA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-double-support"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":57.99999999999999}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingDoubleSupportPercentage/fraction-0.98","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage","unit":"%","value":0.98}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112434-6","display":"Walking double support [Percentile]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fZymmR4AUJOtr-j1qT76-4KdPVBAvRJViUGHok-7Izs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:flGK88mclfUqADwVs8LcLtZGFiJQpfZcieGreysp2RA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-double-support"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":98}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingDoubleSupportPercentage/fraction-0.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage","unit":"%","value":0.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112434-6","display":"Walking double support [Percentile]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fZymmR4AUJOtr-j1qT76-4KdPVBAvRJViUGHok-7Izs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:flGK88mclfUqADwVs8LcLtZGFiJQpfZcieGreysp2RA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-double-support"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":50}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingDoubleSupportPercentage/fraction-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage","unit":"%","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"112434-6","display":"Walking double support [Percentile]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fZymmR4AUJOtr-j1qT76-4KdPVBAvRJViUGHok-7Izs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:flGK88mclfUqADwVs8LcLtZGFiJQpfZcieGreysp2RA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-double-support"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"%","system":"http://unitsofmeasure.org","unit":"%","value":100}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingHeartRateAverage/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingHeartRateAverage","unit":"count/min","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"walking-heart-rate-average","display":"Walking heart rate average","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingHeartRateAverage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:hCJXdTqY_AMeV-TM3OwjL1MBVM_jELMYJD3cZZ4pXKs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Qf-cuM-RDSE0xjtJAZ6Dy3pykznPG1P6RVDt6PR-g4c"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-heart-rate-average"]},"method":{"coding":[{"code":"daily-mean","display":"Daily mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingHeartRateAverage/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingHeartRateAverage","unit":"count/min","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"walking-heart-rate-average","display":"Walking heart rate average","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingHeartRateAverage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:hCJXdTqY_AMeV-TM3OwjL1MBVM_jELMYJD3cZZ4pXKs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Qf-cuM-RDSE0xjtJAZ6Dy3pykznPG1P6RVDt6PR-g4c"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-heart-rate-average"]},"method":{"coding":[{"code":"daily-mean","display":"Daily mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingHeartRateAverage/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingHeartRateAverage","unit":"count/min","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"walking-heart-rate-average","display":"Walking heart rate average","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingHeartRateAverage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:hCJXdTqY_AMeV-TM3OwjL1MBVM_jELMYJD3cZZ4pXKs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Qf-cuM-RDSE0xjtJAZ6Dy3pykznPG1P6RVDt6PR-g4c"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-heart-rate-average"]},"method":{"coding":[{"code":"daily-mean","display":"Daily mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingHeartRateAverage/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingHeartRateAverage","unit":"count/min","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"walking-heart-rate-average","display":"Walking heart rate average","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingHeartRateAverage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:hCJXdTqY_AMeV-TM3OwjL1MBVM_jELMYJD3cZZ4pXKs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Qf-cuM-RDSE0xjtJAZ6Dy3pykznPG1P6RVDt6PR-g4c"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-heart-rate-average"]},"method":{"coding":[{"code":"daily-mean","display":"Daily mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingHeartRateAverage/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingHeartRateAverage","unit":"count/min","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"walking-heart-rate-average","display":"Walking heart rate average","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingHeartRateAverage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:hCJXdTqY_AMeV-TM3OwjL1MBVM_jELMYJD3cZZ4pXKs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Qf-cuM-RDSE0xjtJAZ6Dy3pykznPG1P6RVDt6PR-g4c"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-heart-rate-average"]},"method":{"coding":[{"code":"daily-mean","display":"Daily mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingHeartRateAverage/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingHeartRateAverage","unit":"count/min","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"walking-heart-rate-average","display":"Walking heart rate average","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingHeartRateAverage"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:hCJXdTqY_AMeV-TM3OwjL1MBVM_jELMYJD3cZZ4pXKs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Qf-cuM-RDSE0xjtJAZ6Dy3pykznPG1P6RVDt6PR-g4c"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-heart-rate-average"]},"method":{"coding":[{"code":"daily-mean","display":"Daily mean","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-aggregation-method"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingHeartRateAverage/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingHeartRateAverage","unit":"count/min","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.walkingHeartRateAverage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingHeartRateAverage/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingHeartRateAverage","unit":"count/min","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.walkingHeartRateAverage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingHeartRateAverage/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingHeartRateAverage","unit":"count/min","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.walkingHeartRateAverage, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingSpeed/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingSpeed","unit":"m/s","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"walking-speed","display":"Walking speed","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:S27dNyjDcEWV33Cfohlh3en_rSGVG1FIbDN8-qm7biE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KC1Fpuh79pjCGhd8UmDFqzqRegbtg_w7MPn9zK98zkM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-speed"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingSpeed/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingSpeed","unit":"m/s","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"walking-speed","display":"Walking speed","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:S27dNyjDcEWV33Cfohlh3en_rSGVG1FIbDN8-qm7biE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KC1Fpuh79pjCGhd8UmDFqzqRegbtg_w7MPn9zK98zkM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-speed"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingSpeed/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingSpeed","unit":"m/s","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"walking-speed","display":"Walking speed","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:S27dNyjDcEWV33Cfohlh3en_rSGVG1FIbDN8-qm7biE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KC1Fpuh79pjCGhd8UmDFqzqRegbtg_w7MPn9zK98zkM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-speed"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingSpeed/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingSpeed","unit":"m/s","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"walking-speed","display":"Walking speed","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:S27dNyjDcEWV33Cfohlh3en_rSGVG1FIbDN8-qm7biE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KC1Fpuh79pjCGhd8UmDFqzqRegbtg_w7MPn9zK98zkM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-speed"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingSpeed/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingSpeed","unit":"m/s","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"walking-speed","display":"Walking speed","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:S27dNyjDcEWV33Cfohlh3en_rSGVG1FIbDN8-qm7biE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KC1Fpuh79pjCGhd8UmDFqzqRegbtg_w7MPn9zK98zkM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-speed"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingSpeed/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingSpeed","unit":"m/s","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"walking-speed","display":"Walking speed","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingSpeed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:S27dNyjDcEWV33Cfohlh3en_rSGVG1FIbDN8-qm7biE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KC1Fpuh79pjCGhd8UmDFqzqRegbtg_w7MPn9zK98zkM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-speed"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"m/s","system":"http://unitsofmeasure.org","unit":"m/s","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingSpeed/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingSpeed","unit":"m/s","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.walkingSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingSpeed/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingSpeed","unit":"m/s","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.walkingSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingSpeed/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingSpeed","unit":"m/s","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.walkingSpeed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingStepLength/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingStepLength","unit":"cm","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"walking-step-length","display":"Walking step length","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingStepLength"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:db-JXr82w5wEHpnJVb46iCQAu8wqi2s0I3XaMvh1y-s"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_gkB4eKondhZ_41gL9vmRD00pGmLdTcu1GBRhLcHIj8"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-step-length"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingStepLength/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingStepLength","unit":"cm","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"walking-step-length","display":"Walking step length","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingStepLength"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:db-JXr82w5wEHpnJVb46iCQAu8wqi2s0I3XaMvh1y-s"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_gkB4eKondhZ_41gL9vmRD00pGmLdTcu1GBRhLcHIj8"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-step-length"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingStepLength/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingStepLength","unit":"cm","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"walking-step-length","display":"Walking step length","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingStepLength"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:db-JXr82w5wEHpnJVb46iCQAu8wqi2s0I3XaMvh1y-s"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_gkB4eKondhZ_41gL9vmRD00pGmLdTcu1GBRhLcHIj8"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-step-length"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingStepLength/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingStepLength","unit":"cm","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"walking-step-length","display":"Walking step length","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingStepLength"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:db-JXr82w5wEHpnJVb46iCQAu8wqi2s0I3XaMvh1y-s"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_gkB4eKondhZ_41gL9vmRD00pGmLdTcu1GBRhLcHIj8"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-step-length"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingStepLength/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingStepLength","unit":"cm","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"walking-step-length","display":"Walking step length","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingStepLength"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:db-JXr82w5wEHpnJVb46iCQAu8wqi2s0I3XaMvh1y-s"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_gkB4eKondhZ_41gL9vmRD00pGmLdTcu1GBRhLcHIj8"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-step-length"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingStepLength/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingStepLength","unit":"cm","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"walking-step-length","display":"Walking step length","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWalkingStepLength"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:db-JXr82w5wEHpnJVb46iCQAu8wqi2s0I3XaMvh1y-s"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_gkB4eKondhZ_41gL9vmRD00pGmLdTcu1GBRhLcHIj8"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-step-length"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"cm","system":"http://unitsofmeasure.org","unit":"cm","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingStepLength/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingStepLength","unit":"cm","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.walkingStepLength, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingStepLength/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingStepLength","unit":"cm","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.walkingStepLength, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWalkingStepLength/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWalkingStepLength","unit":"cm","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.walkingStepLength, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWaterTemperature/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWaterTemperature","unit":"degC","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"water-temperature","display":"Water temperature","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWaterTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_aQBajWR8J9JPeLN8Ykf7ouRjf9J76BkcSI6r-fOl_0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VfUSaEffxBvgaJdziMiGTllEdfD71ckVIQiHkII-K-s"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-water-temperature"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWaterTemperature/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWaterTemperature","unit":"degC","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"water-temperature","display":"Water temperature","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWaterTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_aQBajWR8J9JPeLN8Ykf7ouRjf9J76BkcSI6r-fOl_0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VfUSaEffxBvgaJdziMiGTllEdfD71ckVIQiHkII-K-s"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-water-temperature"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWaterTemperature/1.5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWaterTemperature","unit":"degC","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"water-temperature","display":"Water temperature","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWaterTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_aQBajWR8J9JPeLN8Ykf7ouRjf9J76BkcSI6r-fOl_0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VfUSaEffxBvgaJdziMiGTllEdfD71ckVIQiHkII-K-s"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-water-temperature"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWaterTemperature/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWaterTemperature","unit":"degC","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"water-temperature","display":"Water temperature","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWaterTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_aQBajWR8J9JPeLN8Ykf7ouRjf9J76BkcSI6r-fOl_0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VfUSaEffxBvgaJdziMiGTllEdfD71ckVIQiHkII-K-s"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-water-temperature"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWaterTemperature/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWaterTemperature","unit":"degC","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"water-temperature","display":"Water temperature","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWaterTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_aQBajWR8J9JPeLN8Ykf7ouRjf9J76BkcSI6r-fOl_0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VfUSaEffxBvgaJdziMiGTllEdfD71ckVIQiHkII-K-s"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-water-temperature"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWaterTemperature/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWaterTemperature","unit":"degC","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"water-temperature","display":"Water temperature","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWaterTemperature"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_aQBajWR8J9JPeLN8Ykf7ouRjf9J76BkcSI6r-fOl_0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VfUSaEffxBvgaJdziMiGTllEdfD71ckVIQiHkII-K-s"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-water-temperature"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"Cel","system":"http://unitsofmeasure.org","unit":"Cel","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWaterTemperature/nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWaterTemperature","unit":"degC","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.waterTemperature, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWaterTemperature/inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWaterTemperature","unit":"degC","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.waterTemperature, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWaterTemperature/-inf","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWaterTemperature","unit":"degC","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.waterTemperature, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWorkoutEffortScore/row","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWorkoutEffortScore","unit":"appleEffortScore","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout-effort-score","display":"Workout effort score","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWorkoutEffortScore"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jLdZvRFmjEHuw-7GhvSZLFZvUbUAojzH0qreQnpQwAQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:CKnuZ8UXUOhEaJqWCYP96hTB5ndmqtxjnObDqyVnfdA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-workout-effort-score"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{score}","system":"http://unitsofmeasure.org","unit":"score","value":1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWorkoutEffortScore/0.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWorkoutEffortScore","unit":"appleEffortScore","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout-effort-score","display":"Workout effort score","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWorkoutEffortScore"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jLdZvRFmjEHuw-7GhvSZLFZvUbUAojzH0qreQnpQwAQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:CKnuZ8UXUOhEaJqWCYP96hTB5ndmqtxjnObDqyVnfdA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-workout-effort-score"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{score}","system":"http://unitsofmeasure.org","unit":"score","value":0}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWorkoutEffortScore/1.5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWorkoutEffortScore","unit":"appleEffortScore","value":1.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout-effort-score","display":"Workout effort score","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWorkoutEffortScore"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jLdZvRFmjEHuw-7GhvSZLFZvUbUAojzH0qreQnpQwAQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:CKnuZ8UXUOhEaJqWCYP96hTB5ndmqtxjnObDqyVnfdA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-workout-effort-score"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{score}","system":"http://unitsofmeasure.org","unit":"score","value":1.5}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWorkoutEffortScore/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWorkoutEffortScore","unit":"appleEffortScore","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout-effort-score","display":"Workout effort score","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWorkoutEffortScore"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jLdZvRFmjEHuw-7GhvSZLFZvUbUAojzH0qreQnpQwAQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:CKnuZ8UXUOhEaJqWCYP96hTB5ndmqtxjnObDqyVnfdA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-workout-effort-score"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{score}","system":"http://unitsofmeasure.org","unit":"score","value":-1}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWorkoutEffortScore/1e-07","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWorkoutEffortScore","unit":"appleEffortScore","value":1e-07}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout-effort-score","display":"Workout effort score","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWorkoutEffortScore"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jLdZvRFmjEHuw-7GhvSZLFZvUbUAojzH0qreQnpQwAQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:CKnuZ8UXUOhEaJqWCYP96hTB5ndmqtxjnObDqyVnfdA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-workout-effort-score"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{score}","system":"http://unitsofmeasure.org","unit":"score","value":0.0000001}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWorkoutEffortScore/1e+21","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWorkoutEffortScore","unit":"appleEffortScore","value":1e+21}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout-effort-score","display":"Workout effort score","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierWorkoutEffortScore"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jLdZvRFmjEHuw-7GhvSZLFZvUbUAojzH0qreQnpQwAQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:CKnuZ8UXUOhEaJqWCYP96hTB5ndmqtxjnObDqyVnfdA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-workout-effort-score"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{score}","system":"http://unitsofmeasure.org","unit":"score","value":1000000000000000000000}}],"warnings":[]}]}} +{"id":"quantity/HKQuantityTypeIdentifierWorkoutEffortScore/nan","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWorkoutEffortScore","unit":"appleEffortScore","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.workoutEffortScore, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWorkoutEffortScore/inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWorkoutEffortScore","unit":"appleEffortScore","value":"Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.workoutEffortScore, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"quantity/HKQuantityTypeIdentifierWorkoutEffortScore/-inf","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierWorkoutEffortScore","unit":"appleEffortScore","value":"-Infinity"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.workoutEffortScore, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAbdominalCramps/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAbdominalCramps","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.abdominalCramps, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAbdominalCramps/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAbdominalCramps","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-abdominal-cramps","display":"Abdominal cramps","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierAbdominalCramps"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:SFf2YqyD8XNXGUHrldBRZIndBqNysJDp5RBy8TblX4Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BWUHSvxk1EWbudlHlvSnNhg0dAw6Y-hIqNB9xDPoGxM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-abdominal-cramps"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierAbdominalCramps/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAbdominalCramps","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-abdominal-cramps","display":"Abdominal cramps","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierAbdominalCramps"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:SFf2YqyD8XNXGUHrldBRZIndBqNysJDp5RBy8TblX4Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BWUHSvxk1EWbudlHlvSnNhg0dAw6Y-hIqNB9xDPoGxM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-abdominal-cramps"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierAbdominalCramps/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAbdominalCramps","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-abdominal-cramps","display":"Abdominal cramps","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierAbdominalCramps"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:SFf2YqyD8XNXGUHrldBRZIndBqNysJDp5RBy8TblX4Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BWUHSvxk1EWbudlHlvSnNhg0dAw6Y-hIqNB9xDPoGxM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-abdominal-cramps"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierAbdominalCramps/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAbdominalCramps","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-abdominal-cramps","display":"Abdominal cramps","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierAbdominalCramps"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:SFf2YqyD8XNXGUHrldBRZIndBqNysJDp5RBy8TblX4Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BWUHSvxk1EWbudlHlvSnNhg0dAw6Y-hIqNB9xDPoGxM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-abdominal-cramps"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierAbdominalCramps/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAbdominalCramps","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-abdominal-cramps","display":"Abdominal cramps","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierAbdominalCramps"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:SFf2YqyD8XNXGUHrldBRZIndBqNysJDp5RBy8TblX4Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BWUHSvxk1EWbudlHlvSnNhg0dAw6Y-hIqNB9xDPoGxM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-abdominal-cramps"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierAbdominalCramps/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAbdominalCramps","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.abdominalCramps, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAbdominalCramps/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAbdominalCramps","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.abdominalCramps, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAbdominalCramps/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAbdominalCramps","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.abdominalCramps, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAbdominalCramps/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAbdominalCramps","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.abdominalCramps, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAcne/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAcne","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.acne, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAcne/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAcne","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-acne","display":"Acne","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierAcne"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:17R15R0HZ89PWP7foH6PAiPTl46hJzES3Dj8y-6Wj14"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0k83xV0rv4dDOX8SrhbS9JbrDrmkh25Yoxye1HiSWnY"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-acne"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierAcne/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAcne","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-acne","display":"Acne","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierAcne"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:17R15R0HZ89PWP7foH6PAiPTl46hJzES3Dj8y-6Wj14"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0k83xV0rv4dDOX8SrhbS9JbrDrmkh25Yoxye1HiSWnY"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-acne"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierAcne/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAcne","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-acne","display":"Acne","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierAcne"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:17R15R0HZ89PWP7foH6PAiPTl46hJzES3Dj8y-6Wj14"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0k83xV0rv4dDOX8SrhbS9JbrDrmkh25Yoxye1HiSWnY"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-acne"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierAcne/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAcne","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-acne","display":"Acne","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierAcne"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:17R15R0HZ89PWP7foH6PAiPTl46hJzES3Dj8y-6Wj14"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0k83xV0rv4dDOX8SrhbS9JbrDrmkh25Yoxye1HiSWnY"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-acne"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierAcne/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAcne","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-acne","display":"Acne","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierAcne"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:17R15R0HZ89PWP7foH6PAiPTl46hJzES3Dj8y-6Wj14"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0k83xV0rv4dDOX8SrhbS9JbrDrmkh25Yoxye1HiSWnY"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-acne"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierAcne/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAcne","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.acne, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAcne/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAcne","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.acne, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAcne/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAcne","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.acne, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAcne/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAcne","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.acne, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppetiteChanges/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppetiteChanges","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appetiteChanges, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppetiteChanges/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppetiteChanges","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-appetite-changes","display":"Appetite changes","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierAppetiteChanges"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0rdfnnEp5gLqIlE_WnAz8MsbA-rQqamhS4ofVP4pkMs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ZTkR-x2IMlwUs6ng_QM3qTWucV6FYj2WGD-uSlCsh60"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-appetite-changes"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"change-unspecified","display":"Changed, direction unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-appetite-changes"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-appetite-changes"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierAppetiteChanges/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppetiteChanges","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-appetite-changes","display":"Appetite changes","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierAppetiteChanges"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0rdfnnEp5gLqIlE_WnAz8MsbA-rQqamhS4ofVP4pkMs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ZTkR-x2IMlwUs6ng_QM3qTWucV6FYj2WGD-uSlCsh60"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-appetite-changes"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"no-change","display":"No change","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-appetite-changes"},{"code":"noChange","display":"No change","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-appetite-changes"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierAppetiteChanges/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppetiteChanges","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-appetite-changes","display":"Appetite changes","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierAppetiteChanges"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0rdfnnEp5gLqIlE_WnAz8MsbA-rQqamhS4ofVP4pkMs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ZTkR-x2IMlwUs6ng_QM3qTWucV6FYj2WGD-uSlCsh60"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-appetite-changes"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"decreased","display":"Decreased","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-appetite-changes"},{"code":"decreased","display":"Decreased","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-appetite-changes"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierAppetiteChanges/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppetiteChanges","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-appetite-changes","display":"Appetite changes","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierAppetiteChanges"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0rdfnnEp5gLqIlE_WnAz8MsbA-rQqamhS4ofVP4pkMs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ZTkR-x2IMlwUs6ng_QM3qTWucV6FYj2WGD-uSlCsh60"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-appetite-changes"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"increased","display":"Increased","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-appetite-changes"},{"code":"increased","display":"Increased","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-appetite-changes"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierAppetiteChanges/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppetiteChanges","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appetiteChanges, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppetiteChanges/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppetiteChanges","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appetiteChanges, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppetiteChanges/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppetiteChanges","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appetiteChanges, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppetiteChanges/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppetiteChanges","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appetiteChanges, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppetiteChanges/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppetiteChanges","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appetiteChanges, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppleStandHour/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppleStandHour","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleStandHour, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppleStandHour/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppleStandHour","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"apple-stand-hour","display":"Apple stand hour","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierAppleStandHour"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vb6Mfc21GK9LqlIbMmGIMnrTbves8H15eyJKnpTtrbc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:F5qkX0j8T8ydE-WYzM0JQo3lhE2VYMnbV_7xvuovUe4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-stand-hour"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"stood","display":"Stood","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-apple-stand-hour"},{"code":"stood","display":"Stood","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-apple-stand-hour-value"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierAppleStandHour/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppleStandHour","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"apple-stand-hour","display":"Apple stand hour","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierAppleStandHour"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vb6Mfc21GK9LqlIbMmGIMnrTbves8H15eyJKnpTtrbc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:F5qkX0j8T8ydE-WYzM0JQo3lhE2VYMnbV_7xvuovUe4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-stand-hour"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"idle","display":"Idle","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-apple-stand-hour"},{"code":"idle","display":"Idle","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-apple-stand-hour-value"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierAppleStandHour/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppleStandHour","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleStandHour, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(2))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppleStandHour/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppleStandHour","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleStandHour, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(3))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppleStandHour/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppleStandHour","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleStandHour, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppleStandHour/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppleStandHour","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleStandHour, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppleStandHour/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppleStandHour","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleStandHour, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppleStandHour/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppleStandHour","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleStandHour, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppleStandHour/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppleStandHour","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleStandHour, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppleWalkingSteadinessEvent/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppleWalkingSteadinessEvent","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleWalkingSteadinessEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppleWalkingSteadinessEvent/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppleWalkingSteadinessEvent","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleWalkingSteadinessEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(0))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppleWalkingSteadinessEvent/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppleWalkingSteadinessEvent","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleWalkingSteadinessEvent, GroveHealthKitFHIR.HealthKitValueFailure.missingNormativeCode)","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppleWalkingSteadinessEvent/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppleWalkingSteadinessEvent","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleWalkingSteadinessEvent, GroveHealthKitFHIR.HealthKitValueFailure.missingNormativeCode)","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppleWalkingSteadinessEvent/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppleWalkingSteadinessEvent","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleWalkingSteadinessEvent, GroveHealthKitFHIR.HealthKitValueFailure.missingNormativeCode)","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppleWalkingSteadinessEvent/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppleWalkingSteadinessEvent","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleWalkingSteadinessEvent, GroveHealthKitFHIR.HealthKitValueFailure.missingNormativeCode)","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppleWalkingSteadinessEvent/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppleWalkingSteadinessEvent","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleWalkingSteadinessEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppleWalkingSteadinessEvent/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppleWalkingSteadinessEvent","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleWalkingSteadinessEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppleWalkingSteadinessEvent/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppleWalkingSteadinessEvent","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleWalkingSteadinessEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAppleWalkingSteadinessEvent/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAppleWalkingSteadinessEvent","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.appleWalkingSteadinessEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAudioExposureEvent/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAudioExposureEvent","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.audioExposureEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAudioExposureEvent/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAudioExposureEvent","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.audioExposureEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(0))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAudioExposureEvent/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAudioExposureEvent","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"environmental-audio-exposure-notification","display":"Environmental Audio Exposure Notification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierAudioExposureEvent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ZDMIUswVgx9GrQ1O-m_SVSGmS6fxAJGxoGHzWOyknco"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-iCXTqbbBskyri7IcaBCfFLZpRAInufs3lpYL0l-7tA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-environmental-audio-exposure-notification"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"momentary-limit","display":"Momentary limit","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-environmental-audio-exposure-notification"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierAudioExposureEvent/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAudioExposureEvent","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.audioExposureEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(2))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAudioExposureEvent/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAudioExposureEvent","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.audioExposureEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(3))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAudioExposureEvent/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAudioExposureEvent","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.audioExposureEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAudioExposureEvent/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAudioExposureEvent","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.audioExposureEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAudioExposureEvent/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAudioExposureEvent","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.audioExposureEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAudioExposureEvent/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAudioExposureEvent","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.audioExposureEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierAudioExposureEvent/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierAudioExposureEvent","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.audioExposureEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBladderIncontinence/-1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBladderIncontinence","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bladderIncontinence, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBladderIncontinence/0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBladderIncontinence","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"bladder-incontinence","display":"Bladder incontinence","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBladderIncontinence"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kQ4b3lipIN-9e6cysU201PWZENPESVzs9cGpYe5Xbug"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:bKe255DsoQeWtXCRRcdGuS-dtR8qlr8ShcRa3FWIcDg"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-bladder-incontinence"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBladderIncontinence/1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBladderIncontinence","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"bladder-incontinence","display":"Bladder incontinence","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBladderIncontinence"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kQ4b3lipIN-9e6cysU201PWZENPESVzs9cGpYe5Xbug"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:bKe255DsoQeWtXCRRcdGuS-dtR8qlr8ShcRa3FWIcDg"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-bladder-incontinence"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBladderIncontinence/2","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBladderIncontinence","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"bladder-incontinence","display":"Bladder incontinence","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBladderIncontinence"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kQ4b3lipIN-9e6cysU201PWZENPESVzs9cGpYe5Xbug"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:bKe255DsoQeWtXCRRcdGuS-dtR8qlr8ShcRa3FWIcDg"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-bladder-incontinence"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBladderIncontinence/3","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBladderIncontinence","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"bladder-incontinence","display":"Bladder incontinence","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBladderIncontinence"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kQ4b3lipIN-9e6cysU201PWZENPESVzs9cGpYe5Xbug"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:bKe255DsoQeWtXCRRcdGuS-dtR8qlr8ShcRa3FWIcDg"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-bladder-incontinence"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBladderIncontinence/4","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBladderIncontinence","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"bladder-incontinence","display":"Bladder incontinence","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBladderIncontinence"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kQ4b3lipIN-9e6cysU201PWZENPESVzs9cGpYe5Xbug"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:bKe255DsoQeWtXCRRcdGuS-dtR8qlr8ShcRa3FWIcDg"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-bladder-incontinence"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBladderIncontinence/5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBladderIncontinence","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bladderIncontinence, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBladderIncontinence/6","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBladderIncontinence","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bladderIncontinence, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBladderIncontinence/7","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBladderIncontinence","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bladderIncontinence, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBladderIncontinence/8","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBladderIncontinence","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bladderIncontinence, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBleedingAfterPregnancy/-1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBleedingAfterPregnancy","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bleedingAfterPregnancy, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBleedingAfterPregnancy/0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBleedingAfterPregnancy","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bleedingAfterPregnancy, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(0))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBleedingAfterPregnancy/1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBleedingAfterPregnancy","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"bleeding-after-pregnancy","display":"Bleeding after pregnancy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBleedingAfterPregnancy"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:c__qlr9V0FSMo__XlnC5vegRMY7DjK938IbO7RpA8_g"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:O0CSe5uH-g35_KP_WE07M3zA0jsz97swtcUoDUeOVT8"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-bleeding-after-pregnancy"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-bleeding-after-pregnancy"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-vaginal-bleeding"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBleedingAfterPregnancy/2","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBleedingAfterPregnancy","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"bleeding-after-pregnancy","display":"Bleeding after pregnancy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBleedingAfterPregnancy"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:c__qlr9V0FSMo__XlnC5vegRMY7DjK938IbO7RpA8_g"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:O0CSe5uH-g35_KP_WE07M3zA0jsz97swtcUoDUeOVT8"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-bleeding-after-pregnancy"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"light","display":"Light","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-bleeding-after-pregnancy"},{"code":"light","display":"Light","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-vaginal-bleeding"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBleedingAfterPregnancy/3","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBleedingAfterPregnancy","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"bleeding-after-pregnancy","display":"Bleeding after pregnancy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBleedingAfterPregnancy"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:c__qlr9V0FSMo__XlnC5vegRMY7DjK938IbO7RpA8_g"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:O0CSe5uH-g35_KP_WE07M3zA0jsz97swtcUoDUeOVT8"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-bleeding-after-pregnancy"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"medium","display":"Medium","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-bleeding-after-pregnancy"},{"code":"medium","display":"Medium","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-vaginal-bleeding"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBleedingAfterPregnancy/4","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBleedingAfterPregnancy","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"bleeding-after-pregnancy","display":"Bleeding after pregnancy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBleedingAfterPregnancy"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:c__qlr9V0FSMo__XlnC5vegRMY7DjK938IbO7RpA8_g"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:O0CSe5uH-g35_KP_WE07M3zA0jsz97swtcUoDUeOVT8"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-bleeding-after-pregnancy"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"heavy","display":"Heavy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-bleeding-after-pregnancy"},{"code":"heavy","display":"Heavy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-vaginal-bleeding"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBleedingAfterPregnancy/5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBleedingAfterPregnancy","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"bleeding-after-pregnancy","display":"Bleeding after pregnancy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBleedingAfterPregnancy"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:c__qlr9V0FSMo__XlnC5vegRMY7DjK938IbO7RpA8_g"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:O0CSe5uH-g35_KP_WE07M3zA0jsz97swtcUoDUeOVT8"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-bleeding-after-pregnancy"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"none","display":"None","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-bleeding-after-pregnancy"},{"code":"none","display":"None","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-vaginal-bleeding"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBleedingAfterPregnancy/6","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBleedingAfterPregnancy","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bleedingAfterPregnancy, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBleedingAfterPregnancy/7","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBleedingAfterPregnancy","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bleedingAfterPregnancy, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBleedingAfterPregnancy/8","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBleedingAfterPregnancy","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bleedingAfterPregnancy, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBleedingDuringPregnancy/-1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBleedingDuringPregnancy","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bleedingDuringPregnancy, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBleedingDuringPregnancy/0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBleedingDuringPregnancy","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bleedingDuringPregnancy, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(0))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBleedingDuringPregnancy/1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBleedingDuringPregnancy","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"bleeding-during-pregnancy","display":"Bleeding during pregnancy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBleedingDuringPregnancy"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:8rgQlZ0NnAnMUs56LPVlPpy38E4zbVAmpmBgEdIVzVA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dfqSrJx2S0wyYD3m_mLXDjC38DYrOca6c7npEs3tyt0"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-bleeding-during-pregnancy"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-bleeding-during-pregnancy"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-vaginal-bleeding"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBleedingDuringPregnancy/2","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBleedingDuringPregnancy","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"bleeding-during-pregnancy","display":"Bleeding during pregnancy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBleedingDuringPregnancy"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:8rgQlZ0NnAnMUs56LPVlPpy38E4zbVAmpmBgEdIVzVA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dfqSrJx2S0wyYD3m_mLXDjC38DYrOca6c7npEs3tyt0"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-bleeding-during-pregnancy"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"light","display":"Light","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-bleeding-during-pregnancy"},{"code":"light","display":"Light","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-vaginal-bleeding"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBleedingDuringPregnancy/3","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBleedingDuringPregnancy","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"bleeding-during-pregnancy","display":"Bleeding during pregnancy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBleedingDuringPregnancy"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:8rgQlZ0NnAnMUs56LPVlPpy38E4zbVAmpmBgEdIVzVA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dfqSrJx2S0wyYD3m_mLXDjC38DYrOca6c7npEs3tyt0"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-bleeding-during-pregnancy"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"medium","display":"Medium","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-bleeding-during-pregnancy"},{"code":"medium","display":"Medium","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-vaginal-bleeding"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBleedingDuringPregnancy/4","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBleedingDuringPregnancy","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"bleeding-during-pregnancy","display":"Bleeding during pregnancy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBleedingDuringPregnancy"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:8rgQlZ0NnAnMUs56LPVlPpy38E4zbVAmpmBgEdIVzVA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dfqSrJx2S0wyYD3m_mLXDjC38DYrOca6c7npEs3tyt0"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-bleeding-during-pregnancy"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"heavy","display":"Heavy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-bleeding-during-pregnancy"},{"code":"heavy","display":"Heavy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-vaginal-bleeding"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBleedingDuringPregnancy/5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBleedingDuringPregnancy","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"bleeding-during-pregnancy","display":"Bleeding during pregnancy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBleedingDuringPregnancy"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:8rgQlZ0NnAnMUs56LPVlPpy38E4zbVAmpmBgEdIVzVA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dfqSrJx2S0wyYD3m_mLXDjC38DYrOca6c7npEs3tyt0"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-bleeding-during-pregnancy"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"none","display":"None","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-bleeding-during-pregnancy"},{"code":"none","display":"None","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-vaginal-bleeding"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBleedingDuringPregnancy/6","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBleedingDuringPregnancy","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bleedingDuringPregnancy, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBleedingDuringPregnancy/7","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBleedingDuringPregnancy","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bleedingDuringPregnancy, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBleedingDuringPregnancy/8","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBleedingDuringPregnancy","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bleedingDuringPregnancy, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBloating/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBloating","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bloating, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBloating/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBloating","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-bloating","display":"Bloating","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBloating"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MjKeQSco9yGgyWdbkTVHWfa19ZDHh8BVYe6lpcAvCtg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2Ol4dL_K_7arRIP67HZRk0Gr4pipq_CBp9_xonDynqk"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-bloating"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBloating/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBloating","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-bloating","display":"Bloating","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBloating"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MjKeQSco9yGgyWdbkTVHWfa19ZDHh8BVYe6lpcAvCtg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2Ol4dL_K_7arRIP67HZRk0Gr4pipq_CBp9_xonDynqk"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-bloating"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBloating/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBloating","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-bloating","display":"Bloating","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBloating"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MjKeQSco9yGgyWdbkTVHWfa19ZDHh8BVYe6lpcAvCtg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2Ol4dL_K_7arRIP67HZRk0Gr4pipq_CBp9_xonDynqk"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-bloating"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBloating/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBloating","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-bloating","display":"Bloating","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBloating"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MjKeQSco9yGgyWdbkTVHWfa19ZDHh8BVYe6lpcAvCtg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2Ol4dL_K_7arRIP67HZRk0Gr4pipq_CBp9_xonDynqk"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-bloating"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBloating/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBloating","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-bloating","display":"Bloating","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBloating"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MjKeQSco9yGgyWdbkTVHWfa19ZDHh8BVYe6lpcAvCtg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2Ol4dL_K_7arRIP67HZRk0Gr4pipq_CBp9_xonDynqk"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-bloating"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBloating/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBloating","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bloating, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBloating/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBloating","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bloating, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBloating/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBloating","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bloating, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBloating/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBloating","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bloating, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBreastPain/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBreastPain","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.breastPain, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBreastPain/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBreastPain","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-breast-pain","display":"Breast pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBreastPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:8ST6VANlxe5jPl89UO2ZVimZkwMnESz6YjvQCJsZR34"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:aCD6ZHuJRMs902PhicWWieMWTp_3wdOIv7XX3NYPDwA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-breast-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBreastPain/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBreastPain","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-breast-pain","display":"Breast pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBreastPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:8ST6VANlxe5jPl89UO2ZVimZkwMnESz6YjvQCJsZR34"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:aCD6ZHuJRMs902PhicWWieMWTp_3wdOIv7XX3NYPDwA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-breast-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBreastPain/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBreastPain","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-breast-pain","display":"Breast pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBreastPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:8ST6VANlxe5jPl89UO2ZVimZkwMnESz6YjvQCJsZR34"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:aCD6ZHuJRMs902PhicWWieMWTp_3wdOIv7XX3NYPDwA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-breast-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBreastPain/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBreastPain","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-breast-pain","display":"Breast pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBreastPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:8ST6VANlxe5jPl89UO2ZVimZkwMnESz6YjvQCJsZR34"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:aCD6ZHuJRMs902PhicWWieMWTp_3wdOIv7XX3NYPDwA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-breast-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBreastPain/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBreastPain","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-breast-pain","display":"Breast pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierBreastPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:8ST6VANlxe5jPl89UO2ZVimZkwMnESz6YjvQCJsZR34"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:aCD6ZHuJRMs902PhicWWieMWTp_3wdOIv7XX3NYPDwA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-breast-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierBreastPain/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBreastPain","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.breastPain, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBreastPain/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBreastPain","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.breastPain, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBreastPain/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBreastPain","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.breastPain, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierBreastPain/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierBreastPain","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.breastPain, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierCervicalMucusQuality/-1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierCervicalMucusQuality","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.cervicalMucusQuality, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierCervicalMucusQuality/0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierCervicalMucusQuality","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.cervicalMucusQuality, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(0))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierCervicalMucusQuality/1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierCervicalMucusQuality","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"cervical-mucus-quality","display":"Cervical mucus quality","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierCervicalMucusQuality"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:si19EezCZPDkGvupxQ_Zwqo076hzZeJsYw2aGsfjk7s"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:bZbGQvdQDBe_CTKOS3APnVsH-0h00FOIh2YIDCui5X0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-cervical-mucus-quality","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"dry","display":"Dry","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-cervical-mucus-quality"},{"code":"dry","display":"Dry","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-cervical-mucus-quality"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierCervicalMucusQuality/2","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierCervicalMucusQuality","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"cervical-mucus-quality","display":"Cervical mucus quality","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierCervicalMucusQuality"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:si19EezCZPDkGvupxQ_Zwqo076hzZeJsYw2aGsfjk7s"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:bZbGQvdQDBe_CTKOS3APnVsH-0h00FOIh2YIDCui5X0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-cervical-mucus-quality","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"sticky","display":"Sticky","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-cervical-mucus-quality"},{"code":"sticky","display":"Sticky","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-cervical-mucus-quality"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierCervicalMucusQuality/3","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierCervicalMucusQuality","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"cervical-mucus-quality","display":"Cervical mucus quality","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierCervicalMucusQuality"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:si19EezCZPDkGvupxQ_Zwqo076hzZeJsYw2aGsfjk7s"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:bZbGQvdQDBe_CTKOS3APnVsH-0h00FOIh2YIDCui5X0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-cervical-mucus-quality","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"creamy","display":"Creamy","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-cervical-mucus-quality"},{"code":"creamy","display":"Creamy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-cervical-mucus-quality"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierCervicalMucusQuality/4","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierCervicalMucusQuality","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"cervical-mucus-quality","display":"Cervical mucus quality","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierCervicalMucusQuality"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:si19EezCZPDkGvupxQ_Zwqo076hzZeJsYw2aGsfjk7s"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:bZbGQvdQDBe_CTKOS3APnVsH-0h00FOIh2YIDCui5X0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-cervical-mucus-quality","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"watery","display":"Watery","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-cervical-mucus-quality"},{"code":"watery","display":"Watery","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-cervical-mucus-quality"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierCervicalMucusQuality/5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierCervicalMucusQuality","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"cervical-mucus-quality","display":"Cervical mucus quality","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierCervicalMucusQuality"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:si19EezCZPDkGvupxQ_Zwqo076hzZeJsYw2aGsfjk7s"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:bZbGQvdQDBe_CTKOS3APnVsH-0h00FOIh2YIDCui5X0"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-cervical-mucus-quality","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"egg-white","display":"Egg white","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-cervical-mucus-quality"},{"code":"eggWhite","display":"Egg white","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-cervical-mucus-quality"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierCervicalMucusQuality/6","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierCervicalMucusQuality","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.cervicalMucusQuality, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierCervicalMucusQuality/7","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierCervicalMucusQuality","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.cervicalMucusQuality, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierCervicalMucusQuality/8","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierCervicalMucusQuality","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.cervicalMucusQuality, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierChestTightnessOrPain/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierChestTightnessOrPain","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.chestTightnessOrPain, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierChestTightnessOrPain/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierChestTightnessOrPain","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-chest-tightness-or-pain","display":"Chest tightness or pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierChestTightnessOrPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:T4gNeh4Bk77NXZ1G6uyBYIiWQCcYC5yM6GJm7oUuqUk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Lw3JVv6KA9zpIWgSOLWEwlj2xKGLWsJMcFOHp3d_baQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-chest-tightness-or-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierChestTightnessOrPain/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierChestTightnessOrPain","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-chest-tightness-or-pain","display":"Chest tightness or pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierChestTightnessOrPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:T4gNeh4Bk77NXZ1G6uyBYIiWQCcYC5yM6GJm7oUuqUk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Lw3JVv6KA9zpIWgSOLWEwlj2xKGLWsJMcFOHp3d_baQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-chest-tightness-or-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierChestTightnessOrPain/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierChestTightnessOrPain","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-chest-tightness-or-pain","display":"Chest tightness or pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierChestTightnessOrPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:T4gNeh4Bk77NXZ1G6uyBYIiWQCcYC5yM6GJm7oUuqUk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Lw3JVv6KA9zpIWgSOLWEwlj2xKGLWsJMcFOHp3d_baQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-chest-tightness-or-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierChestTightnessOrPain/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierChestTightnessOrPain","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-chest-tightness-or-pain","display":"Chest tightness or pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierChestTightnessOrPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:T4gNeh4Bk77NXZ1G6uyBYIiWQCcYC5yM6GJm7oUuqUk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Lw3JVv6KA9zpIWgSOLWEwlj2xKGLWsJMcFOHp3d_baQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-chest-tightness-or-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierChestTightnessOrPain/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierChestTightnessOrPain","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-chest-tightness-or-pain","display":"Chest tightness or pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierChestTightnessOrPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:T4gNeh4Bk77NXZ1G6uyBYIiWQCcYC5yM6GJm7oUuqUk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Lw3JVv6KA9zpIWgSOLWEwlj2xKGLWsJMcFOHp3d_baQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-chest-tightness-or-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierChestTightnessOrPain/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierChestTightnessOrPain","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.chestTightnessOrPain, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierChestTightnessOrPain/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierChestTightnessOrPain","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.chestTightnessOrPain, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierChestTightnessOrPain/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierChestTightnessOrPain","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.chestTightnessOrPain, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierChestTightnessOrPain/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierChestTightnessOrPain","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.chestTightnessOrPain, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierChills/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierChills","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.chills, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierChills/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierChills","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-chills","display":"Chills","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierChills"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:N1-sZFbkrLRQCMTkJCvrdMk02yQAcdEhlN-6uDgBB58"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:IKHfap3O-8cwiyFNaAoZHBOkdoYtZdqs0wra8J-LXfk"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-chills"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierChills/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierChills","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-chills","display":"Chills","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierChills"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:N1-sZFbkrLRQCMTkJCvrdMk02yQAcdEhlN-6uDgBB58"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:IKHfap3O-8cwiyFNaAoZHBOkdoYtZdqs0wra8J-LXfk"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-chills"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierChills/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierChills","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-chills","display":"Chills","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierChills"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:N1-sZFbkrLRQCMTkJCvrdMk02yQAcdEhlN-6uDgBB58"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:IKHfap3O-8cwiyFNaAoZHBOkdoYtZdqs0wra8J-LXfk"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-chills"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierChills/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierChills","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-chills","display":"Chills","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierChills"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:N1-sZFbkrLRQCMTkJCvrdMk02yQAcdEhlN-6uDgBB58"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:IKHfap3O-8cwiyFNaAoZHBOkdoYtZdqs0wra8J-LXfk"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-chills"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierChills/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierChills","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-chills","display":"Chills","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierChills"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:N1-sZFbkrLRQCMTkJCvrdMk02yQAcdEhlN-6uDgBB58"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:IKHfap3O-8cwiyFNaAoZHBOkdoYtZdqs0wra8J-LXfk"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-chills"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierChills/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierChills","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.chills, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierChills/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierChills","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.chills, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierChills/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierChills","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.chills, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierChills/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierChills","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.chills, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierConstipation/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierConstipation","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.constipation, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierConstipation/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierConstipation","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-constipation","display":"Constipation","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierConstipation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4-qEpfV2LNYYW4G7wfWQLkG4Pwc2bHibsPn1wQPuqXM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2lVN-2BrrS32sO63zzua6uTRgZjBUHAXoh0ITCGhYkQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-constipation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierConstipation/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierConstipation","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-constipation","display":"Constipation","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierConstipation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4-qEpfV2LNYYW4G7wfWQLkG4Pwc2bHibsPn1wQPuqXM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2lVN-2BrrS32sO63zzua6uTRgZjBUHAXoh0ITCGhYkQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-constipation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierConstipation/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierConstipation","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-constipation","display":"Constipation","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierConstipation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4-qEpfV2LNYYW4G7wfWQLkG4Pwc2bHibsPn1wQPuqXM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2lVN-2BrrS32sO63zzua6uTRgZjBUHAXoh0ITCGhYkQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-constipation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierConstipation/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierConstipation","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-constipation","display":"Constipation","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierConstipation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4-qEpfV2LNYYW4G7wfWQLkG4Pwc2bHibsPn1wQPuqXM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2lVN-2BrrS32sO63zzua6uTRgZjBUHAXoh0ITCGhYkQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-constipation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierConstipation/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierConstipation","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-constipation","display":"Constipation","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierConstipation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4-qEpfV2LNYYW4G7wfWQLkG4Pwc2bHibsPn1wQPuqXM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2lVN-2BrrS32sO63zzua6uTRgZjBUHAXoh0ITCGhYkQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-constipation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierConstipation/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierConstipation","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.constipation, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierConstipation/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierConstipation","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.constipation, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierConstipation/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierConstipation","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.constipation, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierConstipation/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierConstipation","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.constipation, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierContraceptive/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierContraceptive","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.contraceptive, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierContraceptive/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierContraceptive","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.contraceptive, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(0))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierContraceptive/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierContraceptive","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"8659-5","display":"Birth control method - Reported","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierContraceptive"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4n_pWkLXWt5vxu22cMqXv5avDiZtLAtBz97ftKiU5e8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:CwF4NQXHkhALu36DUCC9PF6EHARYwBvsjIc0sbP4aBs"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-contraceptive-use"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-contraceptive-use"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-contraceptive"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierContraceptive/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierContraceptive","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"8659-5","display":"Birth control method - Reported","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierContraceptive"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4n_pWkLXWt5vxu22cMqXv5avDiZtLAtBz97ftKiU5e8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:CwF4NQXHkhALu36DUCC9PF6EHARYwBvsjIc0sbP4aBs"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-contraceptive-use"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"implant","display":"Implant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-contraceptive-use"},{"code":"implant","display":"Implant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-contraceptive"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierContraceptive/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierContraceptive","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"8659-5","display":"Birth control method - Reported","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierContraceptive"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4n_pWkLXWt5vxu22cMqXv5avDiZtLAtBz97ftKiU5e8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:CwF4NQXHkhALu36DUCC9PF6EHARYwBvsjIc0sbP4aBs"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-contraceptive-use"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"injection","display":"Injection","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-contraceptive-use"},{"code":"injection","display":"Injection","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-contraceptive"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierContraceptive/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierContraceptive","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"8659-5","display":"Birth control method - Reported","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierContraceptive"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4n_pWkLXWt5vxu22cMqXv5avDiZtLAtBz97ftKiU5e8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:CwF4NQXHkhALu36DUCC9PF6EHARYwBvsjIc0sbP4aBs"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-contraceptive-use"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"intrauterine-device","display":"Intrauterine device","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-contraceptive-use"},{"code":"intrauterineDevice","display":"Intrauterine device","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-contraceptive"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierContraceptive/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierContraceptive","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"8659-5","display":"Birth control method - Reported","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierContraceptive"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4n_pWkLXWt5vxu22cMqXv5avDiZtLAtBz97ftKiU5e8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:CwF4NQXHkhALu36DUCC9PF6EHARYwBvsjIc0sbP4aBs"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-contraceptive-use"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"intravaginal-ring","display":"Intravaginal ring","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-contraceptive-use"},{"code":"intravaginalRing","display":"Intravaginal ring","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-contraceptive"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierContraceptive/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierContraceptive","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"8659-5","display":"Birth control method - Reported","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierContraceptive"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4n_pWkLXWt5vxu22cMqXv5avDiZtLAtBz97ftKiU5e8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:CwF4NQXHkhALu36DUCC9PF6EHARYwBvsjIc0sbP4aBs"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-contraceptive-use"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"oral","display":"Oral","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-contraceptive-use"},{"code":"oral","display":"Oral","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-contraceptive"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierContraceptive/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierContraceptive","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"8659-5","display":"Birth control method - Reported","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierContraceptive"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4n_pWkLXWt5vxu22cMqXv5avDiZtLAtBz97ftKiU5e8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:CwF4NQXHkhALu36DUCC9PF6EHARYwBvsjIc0sbP4aBs"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-contraceptive-use"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"patch","display":"Patch","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-contraceptive-use"},{"code":"patch","display":"Patch","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-contraceptive"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierContraceptive/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierContraceptive","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.contraceptive, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierCoughing/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierCoughing","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.coughing, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierCoughing/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierCoughing","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-coughing","display":"Coughing","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierCoughing"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WavObebfcjDDbAhUOl5cbQ59SCHzYKGa8QDQEC9CZTc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qJsHDskS1PWg3gVeify1nBHeceRthS0aKeFvqUA4tlE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-coughing"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierCoughing/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierCoughing","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-coughing","display":"Coughing","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierCoughing"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WavObebfcjDDbAhUOl5cbQ59SCHzYKGa8QDQEC9CZTc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qJsHDskS1PWg3gVeify1nBHeceRthS0aKeFvqUA4tlE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-coughing"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierCoughing/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierCoughing","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-coughing","display":"Coughing","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierCoughing"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WavObebfcjDDbAhUOl5cbQ59SCHzYKGa8QDQEC9CZTc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qJsHDskS1PWg3gVeify1nBHeceRthS0aKeFvqUA4tlE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-coughing"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierCoughing/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierCoughing","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-coughing","display":"Coughing","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierCoughing"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WavObebfcjDDbAhUOl5cbQ59SCHzYKGa8QDQEC9CZTc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qJsHDskS1PWg3gVeify1nBHeceRthS0aKeFvqUA4tlE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-coughing"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierCoughing/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierCoughing","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-coughing","display":"Coughing","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierCoughing"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WavObebfcjDDbAhUOl5cbQ59SCHzYKGa8QDQEC9CZTc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:qJsHDskS1PWg3gVeify1nBHeceRthS0aKeFvqUA4tlE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-coughing"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierCoughing/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierCoughing","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.coughing, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierCoughing/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierCoughing","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.coughing, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierCoughing/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierCoughing","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.coughing, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierCoughing/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierCoughing","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.coughing, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierDiarrhea/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDiarrhea","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.diarrhea, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierDiarrhea/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDiarrhea","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-diarrhea","display":"Diarrhea","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierDiarrhea"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:UI_jnZuvHiD7BTt1cZTEIjdoNuIy48Pte7caBPP4Ln4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xFqUHL8d7nH6SUYf8KK6fCiStkv0R4tDntgjEAfDSRA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-diarrhea"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierDiarrhea/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDiarrhea","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-diarrhea","display":"Diarrhea","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierDiarrhea"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:UI_jnZuvHiD7BTt1cZTEIjdoNuIy48Pte7caBPP4Ln4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xFqUHL8d7nH6SUYf8KK6fCiStkv0R4tDntgjEAfDSRA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-diarrhea"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierDiarrhea/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDiarrhea","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-diarrhea","display":"Diarrhea","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierDiarrhea"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:UI_jnZuvHiD7BTt1cZTEIjdoNuIy48Pte7caBPP4Ln4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xFqUHL8d7nH6SUYf8KK6fCiStkv0R4tDntgjEAfDSRA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-diarrhea"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierDiarrhea/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDiarrhea","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-diarrhea","display":"Diarrhea","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierDiarrhea"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:UI_jnZuvHiD7BTt1cZTEIjdoNuIy48Pte7caBPP4Ln4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xFqUHL8d7nH6SUYf8KK6fCiStkv0R4tDntgjEAfDSRA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-diarrhea"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierDiarrhea/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDiarrhea","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-diarrhea","display":"Diarrhea","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierDiarrhea"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:UI_jnZuvHiD7BTt1cZTEIjdoNuIy48Pte7caBPP4Ln4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xFqUHL8d7nH6SUYf8KK6fCiStkv0R4tDntgjEAfDSRA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-diarrhea"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierDiarrhea/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDiarrhea","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.diarrhea, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierDiarrhea/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDiarrhea","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.diarrhea, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierDiarrhea/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDiarrhea","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.diarrhea, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierDiarrhea/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDiarrhea","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.diarrhea, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierDizziness/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDizziness","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dizziness, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierDizziness/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDizziness","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-dizziness","display":"Dizziness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierDizziness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dE0cr2-2jU_I-sk8VhzgWKxf_GI1g2mk19VVzvsjjpc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:tBw_HTmuXG5cTnYvOK5VUTyk6wNa225-gRa0oSbQOv0"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-dizziness"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierDizziness/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDizziness","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-dizziness","display":"Dizziness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierDizziness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dE0cr2-2jU_I-sk8VhzgWKxf_GI1g2mk19VVzvsjjpc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:tBw_HTmuXG5cTnYvOK5VUTyk6wNa225-gRa0oSbQOv0"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-dizziness"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierDizziness/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDizziness","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-dizziness","display":"Dizziness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierDizziness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dE0cr2-2jU_I-sk8VhzgWKxf_GI1g2mk19VVzvsjjpc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:tBw_HTmuXG5cTnYvOK5VUTyk6wNa225-gRa0oSbQOv0"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-dizziness"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierDizziness/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDizziness","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-dizziness","display":"Dizziness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierDizziness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dE0cr2-2jU_I-sk8VhzgWKxf_GI1g2mk19VVzvsjjpc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:tBw_HTmuXG5cTnYvOK5VUTyk6wNa225-gRa0oSbQOv0"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-dizziness"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierDizziness/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDizziness","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-dizziness","display":"Dizziness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierDizziness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dE0cr2-2jU_I-sk8VhzgWKxf_GI1g2mk19VVzvsjjpc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:tBw_HTmuXG5cTnYvOK5VUTyk6wNa225-gRa0oSbQOv0"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-dizziness"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierDizziness/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDizziness","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dizziness, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierDizziness/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDizziness","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dizziness, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierDizziness/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDizziness","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dizziness, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierDizziness/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDizziness","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dizziness, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierDrySkin/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDrySkin","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.drySkin, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierDrySkin/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDrySkin","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-dry-skin","display":"Dry skin","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierDrySkin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:lcCdeFB78Jd7AJme3l3kUQmf4fyEsN9LkeC9HQmf-Q0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BYLsmSKqtJEitGwPeP2Y_fYQkmnOojvRWY2zb8Csfu4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-dry-skin"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierDrySkin/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDrySkin","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-dry-skin","display":"Dry skin","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierDrySkin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:lcCdeFB78Jd7AJme3l3kUQmf4fyEsN9LkeC9HQmf-Q0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BYLsmSKqtJEitGwPeP2Y_fYQkmnOojvRWY2zb8Csfu4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-dry-skin"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierDrySkin/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDrySkin","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-dry-skin","display":"Dry skin","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierDrySkin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:lcCdeFB78Jd7AJme3l3kUQmf4fyEsN9LkeC9HQmf-Q0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BYLsmSKqtJEitGwPeP2Y_fYQkmnOojvRWY2zb8Csfu4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-dry-skin"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierDrySkin/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDrySkin","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-dry-skin","display":"Dry skin","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierDrySkin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:lcCdeFB78Jd7AJme3l3kUQmf4fyEsN9LkeC9HQmf-Q0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BYLsmSKqtJEitGwPeP2Y_fYQkmnOojvRWY2zb8Csfu4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-dry-skin"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierDrySkin/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDrySkin","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-dry-skin","display":"Dry skin","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierDrySkin"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:lcCdeFB78Jd7AJme3l3kUQmf4fyEsN9LkeC9HQmf-Q0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BYLsmSKqtJEitGwPeP2Y_fYQkmnOojvRWY2zb8Csfu4"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-dry-skin"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierDrySkin/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDrySkin","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.drySkin, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierDrySkin/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDrySkin","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.drySkin, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierDrySkin/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDrySkin","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.drySkin, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierDrySkin/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierDrySkin","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.drySkin, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierFainting/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFainting","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.fainting, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierFainting/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFainting","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-fainting","display":"Fainting","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierFainting"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:aUQQhgh8MTRxnzxwIRqiS0AlY6-2mi_FfjkFiFsen7o"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4XtlWh1vPgYcZlCHrNxvnqkfhVmj0JdR9SB8l-7ro9A"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-fainting"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierFainting/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFainting","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-fainting","display":"Fainting","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierFainting"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:aUQQhgh8MTRxnzxwIRqiS0AlY6-2mi_FfjkFiFsen7o"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4XtlWh1vPgYcZlCHrNxvnqkfhVmj0JdR9SB8l-7ro9A"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-fainting"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierFainting/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFainting","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-fainting","display":"Fainting","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierFainting"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:aUQQhgh8MTRxnzxwIRqiS0AlY6-2mi_FfjkFiFsen7o"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4XtlWh1vPgYcZlCHrNxvnqkfhVmj0JdR9SB8l-7ro9A"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-fainting"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierFainting/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFainting","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-fainting","display":"Fainting","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierFainting"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:aUQQhgh8MTRxnzxwIRqiS0AlY6-2mi_FfjkFiFsen7o"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4XtlWh1vPgYcZlCHrNxvnqkfhVmj0JdR9SB8l-7ro9A"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-fainting"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierFainting/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFainting","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-fainting","display":"Fainting","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierFainting"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:aUQQhgh8MTRxnzxwIRqiS0AlY6-2mi_FfjkFiFsen7o"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4XtlWh1vPgYcZlCHrNxvnqkfhVmj0JdR9SB8l-7ro9A"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-fainting"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierFainting/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFainting","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.fainting, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierFainting/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFainting","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.fainting, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierFainting/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFainting","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.fainting, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierFainting/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFainting","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.fainting, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierFatigue/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFatigue","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.fatigue, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierFatigue/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFatigue","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-fatigue","display":"Fatigue","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierFatigue"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:RFljjuPf3G7j89Jynd-CddopFoz5pB8KyylQ0JWgy7w"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:na3PLyGByvdbKWCWY19d2jJ-_gelcemkA8FTk4TqFhU"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-fatigue"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierFatigue/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFatigue","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-fatigue","display":"Fatigue","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierFatigue"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:RFljjuPf3G7j89Jynd-CddopFoz5pB8KyylQ0JWgy7w"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:na3PLyGByvdbKWCWY19d2jJ-_gelcemkA8FTk4TqFhU"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-fatigue"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierFatigue/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFatigue","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-fatigue","display":"Fatigue","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierFatigue"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:RFljjuPf3G7j89Jynd-CddopFoz5pB8KyylQ0JWgy7w"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:na3PLyGByvdbKWCWY19d2jJ-_gelcemkA8FTk4TqFhU"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-fatigue"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierFatigue/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFatigue","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-fatigue","display":"Fatigue","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierFatigue"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:RFljjuPf3G7j89Jynd-CddopFoz5pB8KyylQ0JWgy7w"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:na3PLyGByvdbKWCWY19d2jJ-_gelcemkA8FTk4TqFhU"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-fatigue"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierFatigue/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFatigue","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-fatigue","display":"Fatigue","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierFatigue"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:RFljjuPf3G7j89Jynd-CddopFoz5pB8KyylQ0JWgy7w"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:na3PLyGByvdbKWCWY19d2jJ-_gelcemkA8FTk4TqFhU"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-fatigue"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierFatigue/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFatigue","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.fatigue, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierFatigue/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFatigue","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.fatigue, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierFatigue/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFatigue","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.fatigue, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierFatigue/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFatigue","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.fatigue, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierFever/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFever","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.fever, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierFever/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFever","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-fever","display":"Fever","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierFever"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0ziPPQNIOEh00yw4UkCVfFIR73wI5M9dRe0eOKih9mk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:nHNjypoVhSgGaSjuiQCnhbpFekFsOfwd9d4nY6vIqCc"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-fever"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierFever/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFever","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-fever","display":"Fever","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierFever"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0ziPPQNIOEh00yw4UkCVfFIR73wI5M9dRe0eOKih9mk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:nHNjypoVhSgGaSjuiQCnhbpFekFsOfwd9d4nY6vIqCc"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-fever"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierFever/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFever","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-fever","display":"Fever","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierFever"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0ziPPQNIOEh00yw4UkCVfFIR73wI5M9dRe0eOKih9mk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:nHNjypoVhSgGaSjuiQCnhbpFekFsOfwd9d4nY6vIqCc"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-fever"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierFever/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFever","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-fever","display":"Fever","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierFever"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0ziPPQNIOEh00yw4UkCVfFIR73wI5M9dRe0eOKih9mk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:nHNjypoVhSgGaSjuiQCnhbpFekFsOfwd9d4nY6vIqCc"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-fever"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierFever/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFever","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-fever","display":"Fever","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierFever"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0ziPPQNIOEh00yw4UkCVfFIR73wI5M9dRe0eOKih9mk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:nHNjypoVhSgGaSjuiQCnhbpFekFsOfwd9d4nY6vIqCc"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-fever"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierFever/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFever","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.fever, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierFever/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFever","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.fever, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierFever/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFever","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.fever, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierFever/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierFever","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.fever, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierGeneralizedBodyAche/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierGeneralizedBodyAche","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.generalizedBodyAche, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierGeneralizedBodyAche/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierGeneralizedBodyAche","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-generalized-body-ache","display":"Generalized body ache","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierGeneralizedBodyAche"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Meq1EiloHaLy63l0-8YNgnRCanewUf9Y2cRYfjyouZI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AlSQT8pWOMLtyIxktMjkrn6HzLcUaEC5YYbNzGmw9Sk"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-generalized-body-ache"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierGeneralizedBodyAche/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierGeneralizedBodyAche","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-generalized-body-ache","display":"Generalized body ache","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierGeneralizedBodyAche"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Meq1EiloHaLy63l0-8YNgnRCanewUf9Y2cRYfjyouZI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AlSQT8pWOMLtyIxktMjkrn6HzLcUaEC5YYbNzGmw9Sk"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-generalized-body-ache"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierGeneralizedBodyAche/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierGeneralizedBodyAche","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-generalized-body-ache","display":"Generalized body ache","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierGeneralizedBodyAche"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Meq1EiloHaLy63l0-8YNgnRCanewUf9Y2cRYfjyouZI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AlSQT8pWOMLtyIxktMjkrn6HzLcUaEC5YYbNzGmw9Sk"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-generalized-body-ache"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierGeneralizedBodyAche/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierGeneralizedBodyAche","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-generalized-body-ache","display":"Generalized body ache","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierGeneralizedBodyAche"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Meq1EiloHaLy63l0-8YNgnRCanewUf9Y2cRYfjyouZI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AlSQT8pWOMLtyIxktMjkrn6HzLcUaEC5YYbNzGmw9Sk"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-generalized-body-ache"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierGeneralizedBodyAche/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierGeneralizedBodyAche","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-generalized-body-ache","display":"Generalized body ache","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierGeneralizedBodyAche"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Meq1EiloHaLy63l0-8YNgnRCanewUf9Y2cRYfjyouZI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AlSQT8pWOMLtyIxktMjkrn6HzLcUaEC5YYbNzGmw9Sk"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-generalized-body-ache"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierGeneralizedBodyAche/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierGeneralizedBodyAche","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.generalizedBodyAche, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierGeneralizedBodyAche/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierGeneralizedBodyAche","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.generalizedBodyAche, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierGeneralizedBodyAche/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierGeneralizedBodyAche","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.generalizedBodyAche, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierGeneralizedBodyAche/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierGeneralizedBodyAche","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.generalizedBodyAche, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHairLoss/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHairLoss","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.hairLoss, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHairLoss/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHairLoss","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-hair-loss","display":"Hair loss","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHairLoss"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:IR1opkYHxcHsi_my__1wAl8ffXIRI_TSnwkywMYM1eg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Lh2-3i7ZCF_6R-GueAcwlARdMrT3bMrOuNlgMk6OC7o"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-hair-loss"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHairLoss/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHairLoss","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-hair-loss","display":"Hair loss","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHairLoss"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:IR1opkYHxcHsi_my__1wAl8ffXIRI_TSnwkywMYM1eg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Lh2-3i7ZCF_6R-GueAcwlARdMrT3bMrOuNlgMk6OC7o"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-hair-loss"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHairLoss/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHairLoss","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-hair-loss","display":"Hair loss","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHairLoss"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:IR1opkYHxcHsi_my__1wAl8ffXIRI_TSnwkywMYM1eg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Lh2-3i7ZCF_6R-GueAcwlARdMrT3bMrOuNlgMk6OC7o"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-hair-loss"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHairLoss/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHairLoss","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-hair-loss","display":"Hair loss","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHairLoss"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:IR1opkYHxcHsi_my__1wAl8ffXIRI_TSnwkywMYM1eg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Lh2-3i7ZCF_6R-GueAcwlARdMrT3bMrOuNlgMk6OC7o"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-hair-loss"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHairLoss/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHairLoss","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-hair-loss","display":"Hair loss","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHairLoss"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:IR1opkYHxcHsi_my__1wAl8ffXIRI_TSnwkywMYM1eg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Lh2-3i7ZCF_6R-GueAcwlARdMrT3bMrOuNlgMk6OC7o"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-hair-loss"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHairLoss/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHairLoss","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.hairLoss, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHairLoss/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHairLoss","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.hairLoss, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHairLoss/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHairLoss","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.hairLoss, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHairLoss/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHairLoss","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.hairLoss, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHandwashingEvent/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHandwashingEvent","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.handwashingEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHandwashingEvent/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHandwashingEvent","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"handwashing-session","display":"Handwashing session","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHandwashingEvent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:6Fy11tWUOZUpKTe0Ys_0zGl3ocMP5Y7oHJV477yjWWs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kxzVpepYqorfwgqCkZya1v8tXMlUzIiVMRy4bEBXqto"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-handwashing-session"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":60}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHandwashingEvent/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHandwashingEvent","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.handwashingEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHandwashingEvent/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHandwashingEvent","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.handwashingEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(2))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHandwashingEvent/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHandwashingEvent","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.handwashingEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(3))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHandwashingEvent/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHandwashingEvent","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.handwashingEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHandwashingEvent/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHandwashingEvent","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.handwashingEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHandwashingEvent/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHandwashingEvent","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.handwashingEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHandwashingEvent/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHandwashingEvent","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.handwashingEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHandwashingEvent/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHandwashingEvent","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.handwashingEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHeadache/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeadache","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.headache, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHeadache/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeadache","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-headache","display":"Headache","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHeadache"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:T7g6kWqEX1U5IYOb7AArnq07Fx6yznhkKxtYhq6EJlU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WzxAoC5vaWc9qHY5cqOQpSRs4qfD2mUfUTyxdG6lCQs"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-headache"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHeadache/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeadache","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-headache","display":"Headache","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHeadache"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:T7g6kWqEX1U5IYOb7AArnq07Fx6yznhkKxtYhq6EJlU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WzxAoC5vaWc9qHY5cqOQpSRs4qfD2mUfUTyxdG6lCQs"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-headache"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHeadache/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeadache","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-headache","display":"Headache","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHeadache"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:T7g6kWqEX1U5IYOb7AArnq07Fx6yznhkKxtYhq6EJlU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WzxAoC5vaWc9qHY5cqOQpSRs4qfD2mUfUTyxdG6lCQs"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-headache"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHeadache/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeadache","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-headache","display":"Headache","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHeadache"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:T7g6kWqEX1U5IYOb7AArnq07Fx6yznhkKxtYhq6EJlU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WzxAoC5vaWc9qHY5cqOQpSRs4qfD2mUfUTyxdG6lCQs"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-headache"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHeadache/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeadache","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-headache","display":"Headache","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHeadache"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:T7g6kWqEX1U5IYOb7AArnq07Fx6yznhkKxtYhq6EJlU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WzxAoC5vaWc9qHY5cqOQpSRs4qfD2mUfUTyxdG6lCQs"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-headache"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHeadache/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeadache","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.headache, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHeadache/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeadache","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.headache, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHeadache/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeadache","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.headache, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHeadache/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeadache","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.headache, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHeadphoneAudioExposureEvent/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeadphoneAudioExposureEvent","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.headphoneAudioExposureEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHeadphoneAudioExposureEvent/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeadphoneAudioExposureEvent","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.headphoneAudioExposureEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(0))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHeadphoneAudioExposureEvent/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeadphoneAudioExposureEvent","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"headphone-audio-exposure-notification","display":"Headphone Audio Exposure Notification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHeadphoneAudioExposureEvent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:uGw4nx283vT80GPFWpIxc32aQE-vUMlkl4tMPGMIu1Q"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:M6dtPpDQiQNY97jaOwLyhYjDcxpuUiCADEsPN1NIMRo"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-headphone-audio-exposure-notification"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"seven-day-limit","display":"Seven day limit","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-headphone-audio-exposure-notification"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHeadphoneAudioExposureEvent/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeadphoneAudioExposureEvent","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.headphoneAudioExposureEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(2))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHeadphoneAudioExposureEvent/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeadphoneAudioExposureEvent","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.headphoneAudioExposureEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(3))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHeadphoneAudioExposureEvent/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeadphoneAudioExposureEvent","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.headphoneAudioExposureEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHeadphoneAudioExposureEvent/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeadphoneAudioExposureEvent","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.headphoneAudioExposureEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHeadphoneAudioExposureEvent/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeadphoneAudioExposureEvent","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.headphoneAudioExposureEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHeadphoneAudioExposureEvent/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeadphoneAudioExposureEvent","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.headphoneAudioExposureEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHeadphoneAudioExposureEvent/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeadphoneAudioExposureEvent","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.headphoneAudioExposureEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHeartburn/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeartburn","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartburn, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHeartburn/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeartburn","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-heartburn","display":"Heartburn","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHeartburn"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ug6qxjn8A83oJ3ov99npHvVvKk5CCevH9a4hpNDlJZM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:8kQdzpgbsmSI8db7wIrQbjsUu25_t_xDklIs9BSzewo"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-heartburn"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHeartburn/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeartburn","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-heartburn","display":"Heartburn","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHeartburn"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ug6qxjn8A83oJ3ov99npHvVvKk5CCevH9a4hpNDlJZM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:8kQdzpgbsmSI8db7wIrQbjsUu25_t_xDklIs9BSzewo"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-heartburn"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHeartburn/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeartburn","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-heartburn","display":"Heartburn","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHeartburn"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ug6qxjn8A83oJ3ov99npHvVvKk5CCevH9a4hpNDlJZM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:8kQdzpgbsmSI8db7wIrQbjsUu25_t_xDklIs9BSzewo"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-heartburn"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHeartburn/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeartburn","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-heartburn","display":"Heartburn","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHeartburn"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ug6qxjn8A83oJ3ov99npHvVvKk5CCevH9a4hpNDlJZM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:8kQdzpgbsmSI8db7wIrQbjsUu25_t_xDklIs9BSzewo"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-heartburn"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHeartburn/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeartburn","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-heartburn","display":"Heartburn","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHeartburn"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ug6qxjn8A83oJ3ov99npHvVvKk5CCevH9a4hpNDlJZM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:8kQdzpgbsmSI8db7wIrQbjsUu25_t_xDklIs9BSzewo"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-heartburn"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHeartburn/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeartburn","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartburn, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHeartburn/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeartburn","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartburn, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHeartburn/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeartburn","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartburn, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHeartburn/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHeartburn","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartburn, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHighHeartRateEvent/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHighHeartRateEvent","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.highHeartRateEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHighHeartRateEvent/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHighHeartRateEvent","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"high-heart-rate-notification","display":"High Heart Rate Notification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHighHeartRateEvent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:TIZ32NOm26lMi-57CTL7fZj5Znf3O8MLCRij1cPWI30"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:flw7kSiSYsr-iveqdkgRbq5iyqK9V-h-NkGfndurIkA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-high-heart-rate-notification"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"occurred","display":"Occurred","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-high-heart-rate-notification"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHighHeartRateEvent/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHighHeartRateEvent","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.highHeartRateEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHighHeartRateEvent/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHighHeartRateEvent","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.highHeartRateEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(2))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHighHeartRateEvent/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHighHeartRateEvent","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.highHeartRateEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(3))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHighHeartRateEvent/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHighHeartRateEvent","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.highHeartRateEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHighHeartRateEvent/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHighHeartRateEvent","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.highHeartRateEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHighHeartRateEvent/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHighHeartRateEvent","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.highHeartRateEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHighHeartRateEvent/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHighHeartRateEvent","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.highHeartRateEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHighHeartRateEvent/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHighHeartRateEvent","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.highHeartRateEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHotFlashes/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHotFlashes","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.hotFlashes, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHotFlashes/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHotFlashes","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-hot-flashes","display":"Hot flashes","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHotFlashes"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NCAdOQWhEl6Pr0i1fHU5kfo6LW_kpcSX4QkL296R8-g"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:M5dXio6aQQJyZ_9LpNKuhKeyrZsHsI2r5Z--vz6kydM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-hot-flashes"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHotFlashes/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHotFlashes","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-hot-flashes","display":"Hot flashes","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHotFlashes"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NCAdOQWhEl6Pr0i1fHU5kfo6LW_kpcSX4QkL296R8-g"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:M5dXio6aQQJyZ_9LpNKuhKeyrZsHsI2r5Z--vz6kydM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-hot-flashes"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHotFlashes/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHotFlashes","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-hot-flashes","display":"Hot flashes","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHotFlashes"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NCAdOQWhEl6Pr0i1fHU5kfo6LW_kpcSX4QkL296R8-g"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:M5dXio6aQQJyZ_9LpNKuhKeyrZsHsI2r5Z--vz6kydM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-hot-flashes"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHotFlashes/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHotFlashes","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-hot-flashes","display":"Hot flashes","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHotFlashes"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NCAdOQWhEl6Pr0i1fHU5kfo6LW_kpcSX4QkL296R8-g"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:M5dXio6aQQJyZ_9LpNKuhKeyrZsHsI2r5Z--vz6kydM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-hot-flashes"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHotFlashes/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHotFlashes","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-hot-flashes","display":"Hot flashes","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHotFlashes"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NCAdOQWhEl6Pr0i1fHU5kfo6LW_kpcSX4QkL296R8-g"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:M5dXio6aQQJyZ_9LpNKuhKeyrZsHsI2r5Z--vz6kydM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-hot-flashes"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHotFlashes/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHotFlashes","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.hotFlashes, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHotFlashes/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHotFlashes","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.hotFlashes, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHotFlashes/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHotFlashes","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.hotFlashes, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHotFlashes/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHotFlashes","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.hotFlashes, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHypertensionEvent/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHypertensionEvent","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.hypertensionEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHypertensionEvent/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHypertensionEvent","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"hypertension-notification","display":"Hypertension Notification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierHypertensionEvent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pCHvj04RbSlhzun3Y3gPJ7QtL3hkxkdClzraTnaIqdI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:LF4Uxf1_aMpQs6QIDUV6GWUBaz6wHD1-X6LX1KwWxPc"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-hypertension-notification"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"occurred","display":"Occurred","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-hypertension-notification"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierHypertensionEvent/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHypertensionEvent","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.hypertensionEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHypertensionEvent/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHypertensionEvent","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.hypertensionEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(2))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHypertensionEvent/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHypertensionEvent","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.hypertensionEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(3))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHypertensionEvent/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHypertensionEvent","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.hypertensionEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHypertensionEvent/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHypertensionEvent","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.hypertensionEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHypertensionEvent/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHypertensionEvent","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.hypertensionEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHypertensionEvent/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHypertensionEvent","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.hypertensionEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierHypertensionEvent/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierHypertensionEvent","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.hypertensionEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierInfrequentMenstrualCycles/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierInfrequentMenstrualCycles","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.infrequentMenstrualCycles, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierInfrequentMenstrualCycles/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierInfrequentMenstrualCycles","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"infrequent-menstrual-cycles","display":"Infrequent menstrual cycles","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierInfrequentMenstrualCycles"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ArcPDDNdH0ozzXnsDs6dqEHQ3perRJI5mh6FhkvVaBU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-euebf521qP-bvYvFd0jubW4b5VDEaElByXNJVlFzv8"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-infrequent-menstrual-cycles"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-infrequent-menstrual-cycles"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierInfrequentMenstrualCycles/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierInfrequentMenstrualCycles","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.infrequentMenstrualCycles, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierInfrequentMenstrualCycles/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierInfrequentMenstrualCycles","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.infrequentMenstrualCycles, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(2))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierInfrequentMenstrualCycles/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierInfrequentMenstrualCycles","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.infrequentMenstrualCycles, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(3))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierInfrequentMenstrualCycles/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierInfrequentMenstrualCycles","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.infrequentMenstrualCycles, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierInfrequentMenstrualCycles/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierInfrequentMenstrualCycles","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.infrequentMenstrualCycles, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierInfrequentMenstrualCycles/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierInfrequentMenstrualCycles","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.infrequentMenstrualCycles, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierInfrequentMenstrualCycles/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierInfrequentMenstrualCycles","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.infrequentMenstrualCycles, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierInfrequentMenstrualCycles/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierInfrequentMenstrualCycles","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.infrequentMenstrualCycles, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIntermenstrualBleeding/-1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIntermenstrualBleeding","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.intermenstrualBleeding, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIntermenstrualBleeding/0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIntermenstrualBleeding","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"intermenstrual-bleeding","display":"Intermenstrual bleeding","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierIntermenstrualBleeding"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:T_C4PHMIR3fXbSAF-2He-vRLysiXEnJD6F_YlHmnETs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:bKoMTKr4cm3CAvJksNYfNNmujgEBJG3weD_CfPiRVCM"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-intermenstrual-bleeding","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-intermenstrual-bleeding"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierIntermenstrualBleeding/1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIntermenstrualBleeding","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.intermenstrualBleeding, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIntermenstrualBleeding/2","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIntermenstrualBleeding","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.intermenstrualBleeding, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(2))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIntermenstrualBleeding/3","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIntermenstrualBleeding","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.intermenstrualBleeding, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(3))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIntermenstrualBleeding/4","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIntermenstrualBleeding","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.intermenstrualBleeding, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIntermenstrualBleeding/5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIntermenstrualBleeding","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.intermenstrualBleeding, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIntermenstrualBleeding/6","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIntermenstrualBleeding","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.intermenstrualBleeding, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIntermenstrualBleeding/7","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIntermenstrualBleeding","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.intermenstrualBleeding, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIntermenstrualBleeding/8","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIntermenstrualBleeding","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.intermenstrualBleeding, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIrregularHeartRhythmEvent/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIrregularHeartRhythmEvent","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.irregularHeartRhythmEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIrregularHeartRhythmEvent/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIrregularHeartRhythmEvent","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"irregular-heart-rhythm-notification","display":"Irregular Heart Rhythm Notification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierIrregularHeartRhythmEvent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:lxJZZ9FNo9CwyLyO1Ty8zuNhSKAkXwDMvm1rEaIUj_U"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:8eStXK6ppOUBT4ts3Uxo8KOaau5db3rT98BIoZIN0jg"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-irregular-heart-rhythm-notification"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"occurred","display":"Occurred","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-irregular-heart-rhythm-notification"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierIrregularHeartRhythmEvent/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIrregularHeartRhythmEvent","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.irregularHeartRhythmEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIrregularHeartRhythmEvent/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIrregularHeartRhythmEvent","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.irregularHeartRhythmEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(2))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIrregularHeartRhythmEvent/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIrregularHeartRhythmEvent","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.irregularHeartRhythmEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(3))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIrregularHeartRhythmEvent/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIrregularHeartRhythmEvent","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.irregularHeartRhythmEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIrregularHeartRhythmEvent/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIrregularHeartRhythmEvent","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.irregularHeartRhythmEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIrregularHeartRhythmEvent/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIrregularHeartRhythmEvent","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.irregularHeartRhythmEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIrregularHeartRhythmEvent/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIrregularHeartRhythmEvent","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.irregularHeartRhythmEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIrregularHeartRhythmEvent/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIrregularHeartRhythmEvent","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.irregularHeartRhythmEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIrregularMenstrualCycles/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIrregularMenstrualCycles","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.irregularMenstrualCycles, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIrregularMenstrualCycles/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIrregularMenstrualCycles","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"irregular-menstrual-cycles","display":"Irregular menstrual cycles","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierIrregularMenstrualCycles"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2qDnsyfLHkozPeKJINISK309ik2Qmtd6PhVXHEezsx8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:moVsYlU6Ec4HrOyMjiRxVQ2tWaiMnjRLgVoY7vsETsU"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-irregular-menstrual-cycles"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-irregular-menstrual-cycles"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierIrregularMenstrualCycles/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIrregularMenstrualCycles","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.irregularMenstrualCycles, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIrregularMenstrualCycles/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIrregularMenstrualCycles","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.irregularMenstrualCycles, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(2))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIrregularMenstrualCycles/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIrregularMenstrualCycles","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.irregularMenstrualCycles, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(3))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIrregularMenstrualCycles/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIrregularMenstrualCycles","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.irregularMenstrualCycles, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIrregularMenstrualCycles/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIrregularMenstrualCycles","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.irregularMenstrualCycles, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIrregularMenstrualCycles/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIrregularMenstrualCycles","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.irregularMenstrualCycles, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIrregularMenstrualCycles/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIrregularMenstrualCycles","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.irregularMenstrualCycles, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierIrregularMenstrualCycles/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierIrregularMenstrualCycles","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.irregularMenstrualCycles, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLactation/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLactation","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lactation, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLactation/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLactation","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"63895-7","display":"Breastfeeding status","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierLactation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KMpGxhHuOJApxGZb7S-sp8HuQSmVHiNkGncw2sNMx0E"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:lKFyBHCLObWVdiif3JJssZVhGP0Wi4jTk4m2yqZL2Rc"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-lactation-status"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"lactating","display":"Lactating","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-lactation-status"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierLactation/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLactation","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lactation, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLactation/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLactation","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lactation, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(2))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLactation/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLactation","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lactation, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(3))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLactation/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLactation","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lactation, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLactation/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLactation","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lactation, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLactation/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLactation","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lactation, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLactation/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLactation","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lactation, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLactation/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLactation","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lactation, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLossOfSmell/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLossOfSmell","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lossOfSmell, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLossOfSmell/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLossOfSmell","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-loss-of-smell","display":"Loss of smell","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierLossOfSmell"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:9K_T9Gxf_8KToImOlIbXOY3e5Ok7n8CcxWryElvQNCg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:R4UvgtjwlIpKNHNZ7p5soy_K2U7AJsEKbMyvC6Lv7qM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-loss-of-smell"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierLossOfSmell/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLossOfSmell","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-loss-of-smell","display":"Loss of smell","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierLossOfSmell"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:9K_T9Gxf_8KToImOlIbXOY3e5Ok7n8CcxWryElvQNCg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:R4UvgtjwlIpKNHNZ7p5soy_K2U7AJsEKbMyvC6Lv7qM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-loss-of-smell"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierLossOfSmell/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLossOfSmell","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-loss-of-smell","display":"Loss of smell","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierLossOfSmell"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:9K_T9Gxf_8KToImOlIbXOY3e5Ok7n8CcxWryElvQNCg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:R4UvgtjwlIpKNHNZ7p5soy_K2U7AJsEKbMyvC6Lv7qM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-loss-of-smell"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierLossOfSmell/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLossOfSmell","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-loss-of-smell","display":"Loss of smell","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierLossOfSmell"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:9K_T9Gxf_8KToImOlIbXOY3e5Ok7n8CcxWryElvQNCg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:R4UvgtjwlIpKNHNZ7p5soy_K2U7AJsEKbMyvC6Lv7qM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-loss-of-smell"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierLossOfSmell/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLossOfSmell","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-loss-of-smell","display":"Loss of smell","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierLossOfSmell"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:9K_T9Gxf_8KToImOlIbXOY3e5Ok7n8CcxWryElvQNCg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:R4UvgtjwlIpKNHNZ7p5soy_K2U7AJsEKbMyvC6Lv7qM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-loss-of-smell"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierLossOfSmell/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLossOfSmell","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lossOfSmell, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLossOfSmell/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLossOfSmell","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lossOfSmell, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLossOfSmell/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLossOfSmell","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lossOfSmell, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLossOfSmell/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLossOfSmell","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lossOfSmell, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLossOfTaste/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLossOfTaste","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lossOfTaste, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLossOfTaste/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLossOfTaste","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-loss-of-taste","display":"Loss of taste","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierLossOfTaste"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:T7mdpyJW5K3X0RBEra7wpZM56zk3x90BEQ8giecv7v8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1ZPKgBUXe_UFpNSp0YE5Y7Fr_DHBOK2uWsZ91u-iQDE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-loss-of-taste"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierLossOfTaste/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLossOfTaste","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-loss-of-taste","display":"Loss of taste","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierLossOfTaste"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:T7mdpyJW5K3X0RBEra7wpZM56zk3x90BEQ8giecv7v8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1ZPKgBUXe_UFpNSp0YE5Y7Fr_DHBOK2uWsZ91u-iQDE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-loss-of-taste"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierLossOfTaste/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLossOfTaste","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-loss-of-taste","display":"Loss of taste","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierLossOfTaste"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:T7mdpyJW5K3X0RBEra7wpZM56zk3x90BEQ8giecv7v8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1ZPKgBUXe_UFpNSp0YE5Y7Fr_DHBOK2uWsZ91u-iQDE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-loss-of-taste"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierLossOfTaste/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLossOfTaste","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-loss-of-taste","display":"Loss of taste","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierLossOfTaste"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:T7mdpyJW5K3X0RBEra7wpZM56zk3x90BEQ8giecv7v8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1ZPKgBUXe_UFpNSp0YE5Y7Fr_DHBOK2uWsZ91u-iQDE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-loss-of-taste"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierLossOfTaste/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLossOfTaste","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-loss-of-taste","display":"Loss of taste","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierLossOfTaste"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:T7mdpyJW5K3X0RBEra7wpZM56zk3x90BEQ8giecv7v8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:1ZPKgBUXe_UFpNSp0YE5Y7Fr_DHBOK2uWsZ91u-iQDE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-loss-of-taste"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierLossOfTaste/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLossOfTaste","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lossOfTaste, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLossOfTaste/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLossOfTaste","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lossOfTaste, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLossOfTaste/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLossOfTaste","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lossOfTaste, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLossOfTaste/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLossOfTaste","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lossOfTaste, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLowCardioFitnessEvent/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowCardioFitnessEvent","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lowCardioFitnessEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLowCardioFitnessEvent/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowCardioFitnessEvent","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lowCardioFitnessEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(0))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLowCardioFitnessEvent/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowCardioFitnessEvent","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"low-cardio-fitness-notification","display":"Low Cardio Fitness Notification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierLowCardioFitnessEvent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:6APz8PKbQ6RpKJLz5qRYUpFXuxnFS92EcjxMEAwETic"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:SX4gfMq0PMTuym8xez1diEYN0Lxu7os5rDcTXBY9Ufw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-low-cardio-fitness-notification"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"low-fitness","display":"Low fitness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-low-cardio-fitness-notification"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierLowCardioFitnessEvent/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowCardioFitnessEvent","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lowCardioFitnessEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(2))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLowCardioFitnessEvent/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowCardioFitnessEvent","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lowCardioFitnessEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(3))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLowCardioFitnessEvent/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowCardioFitnessEvent","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lowCardioFitnessEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLowCardioFitnessEvent/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowCardioFitnessEvent","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lowCardioFitnessEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLowCardioFitnessEvent/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowCardioFitnessEvent","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lowCardioFitnessEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLowCardioFitnessEvent/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowCardioFitnessEvent","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lowCardioFitnessEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLowCardioFitnessEvent/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowCardioFitnessEvent","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lowCardioFitnessEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLowHeartRateEvent/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowHeartRateEvent","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lowHeartRateEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLowHeartRateEvent/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowHeartRateEvent","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"low-heart-rate-notification","display":"Low Heart Rate Notification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierLowHeartRateEvent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:CPGc1PipyG__1KQ7Xg9i8j7Sgbwz3k0fHnyehQmAjXQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:LTPRj6ezDwnTRUXeU_SPpJkyThJ3IT64RH9R5Tq0iOE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-low-heart-rate-notification"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"occurred","display":"Occurred","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-low-heart-rate-notification"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierLowHeartRateEvent/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowHeartRateEvent","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lowHeartRateEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLowHeartRateEvent/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowHeartRateEvent","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lowHeartRateEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(2))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLowHeartRateEvent/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowHeartRateEvent","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lowHeartRateEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(3))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLowHeartRateEvent/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowHeartRateEvent","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lowHeartRateEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLowHeartRateEvent/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowHeartRateEvent","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lowHeartRateEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLowHeartRateEvent/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowHeartRateEvent","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lowHeartRateEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLowHeartRateEvent/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowHeartRateEvent","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lowHeartRateEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLowHeartRateEvent/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowHeartRateEvent","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lowHeartRateEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLowerBackPain/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowerBackPain","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lowerBackPain, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLowerBackPain/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowerBackPain","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-lower-back-pain","display":"Lower back pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierLowerBackPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wtd-fcAXa6dUEk3vyzSi6D7Zv1EkxBsZkPoVi2z6A8Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jez5mjRQ7elrEfgeFTIj8cVLWoBVl6SpA3giCQuP-Ic"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-lower-back-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierLowerBackPain/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowerBackPain","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-lower-back-pain","display":"Lower back pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierLowerBackPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wtd-fcAXa6dUEk3vyzSi6D7Zv1EkxBsZkPoVi2z6A8Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jez5mjRQ7elrEfgeFTIj8cVLWoBVl6SpA3giCQuP-Ic"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-lower-back-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierLowerBackPain/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowerBackPain","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-lower-back-pain","display":"Lower back pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierLowerBackPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wtd-fcAXa6dUEk3vyzSi6D7Zv1EkxBsZkPoVi2z6A8Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jez5mjRQ7elrEfgeFTIj8cVLWoBVl6SpA3giCQuP-Ic"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-lower-back-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierLowerBackPain/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowerBackPain","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-lower-back-pain","display":"Lower back pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierLowerBackPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wtd-fcAXa6dUEk3vyzSi6D7Zv1EkxBsZkPoVi2z6A8Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jez5mjRQ7elrEfgeFTIj8cVLWoBVl6SpA3giCQuP-Ic"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-lower-back-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierLowerBackPain/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowerBackPain","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-lower-back-pain","display":"Lower back pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierLowerBackPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wtd-fcAXa6dUEk3vyzSi6D7Zv1EkxBsZkPoVi2z6A8Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jez5mjRQ7elrEfgeFTIj8cVLWoBVl6SpA3giCQuP-Ic"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-lower-back-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierLowerBackPain/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowerBackPain","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lowerBackPain, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLowerBackPain/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowerBackPain","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lowerBackPain, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLowerBackPain/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowerBackPain","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lowerBackPain, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierLowerBackPain/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierLowerBackPain","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.lowerBackPain, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMemoryLapse/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMemoryLapse","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.memoryLapse, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMemoryLapse/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMemoryLapse","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-memory-lapse","display":"Memory lapse","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierMemoryLapse"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:hm42QLaPHxO5CRmAENujwErsLWPYOhpOeEJcgcbOKaM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vVy3XzciLkXIq5nm6-tNJ9HcZQXBivg2FIOoDsQBLcI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-memory-lapse"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierMemoryLapse/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMemoryLapse","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-memory-lapse","display":"Memory lapse","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierMemoryLapse"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:hm42QLaPHxO5CRmAENujwErsLWPYOhpOeEJcgcbOKaM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vVy3XzciLkXIq5nm6-tNJ9HcZQXBivg2FIOoDsQBLcI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-memory-lapse"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierMemoryLapse/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMemoryLapse","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-memory-lapse","display":"Memory lapse","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierMemoryLapse"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:hm42QLaPHxO5CRmAENujwErsLWPYOhpOeEJcgcbOKaM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vVy3XzciLkXIq5nm6-tNJ9HcZQXBivg2FIOoDsQBLcI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-memory-lapse"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierMemoryLapse/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMemoryLapse","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-memory-lapse","display":"Memory lapse","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierMemoryLapse"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:hm42QLaPHxO5CRmAENujwErsLWPYOhpOeEJcgcbOKaM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vVy3XzciLkXIq5nm6-tNJ9HcZQXBivg2FIOoDsQBLcI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-memory-lapse"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierMemoryLapse/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMemoryLapse","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-memory-lapse","display":"Memory lapse","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierMemoryLapse"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:hm42QLaPHxO5CRmAENujwErsLWPYOhpOeEJcgcbOKaM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vVy3XzciLkXIq5nm6-tNJ9HcZQXBivg2FIOoDsQBLcI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-memory-lapse"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierMemoryLapse/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMemoryLapse","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.memoryLapse, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMemoryLapse/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMemoryLapse","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.memoryLapse, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMemoryLapse/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMemoryLapse","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.memoryLapse, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMemoryLapse/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMemoryLapse","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.memoryLapse, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMenstrualFlow/-1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMenstrualCycleStart":{"boolean":true},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMenstrualFlow","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.menstrualFlow, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMenstrualFlow/0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMenstrualCycleStart":{"boolean":true},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMenstrualFlow","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.menstrualFlow, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(0))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMenstrualFlow/1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMenstrualCycleStart":{"boolean":true},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMenstrualFlow","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"menstruation-flow","display":"Menstruation flow","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"menstrual-cycle-start","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"cycle-start","display":"Cycle start","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-menstrual-cycle-start"}]}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierMenstrualFlow"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zOQPZidTQvTfQKlYbhtjlfByibOVb39p77pRY-BIgRs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:i2VZaK7j7kjlmoihuJaK8_l9eGPvDFPEdHfePQSIu_8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-menstruation-flow","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-menstruation-flow"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-vaginal-bleeding"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierMenstrualFlow/2","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMenstrualCycleStart":{"boolean":true},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMenstrualFlow","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"menstruation-flow","display":"Menstruation flow","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"menstrual-cycle-start","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"cycle-start","display":"Cycle start","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-menstrual-cycle-start"}]}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierMenstrualFlow"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zOQPZidTQvTfQKlYbhtjlfByibOVb39p77pRY-BIgRs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:i2VZaK7j7kjlmoihuJaK8_l9eGPvDFPEdHfePQSIu_8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-menstruation-flow","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"light","display":"Light","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-menstruation-flow"},{"code":"light","display":"Light","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-vaginal-bleeding"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierMenstrualFlow/3","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMenstrualCycleStart":{"boolean":true},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMenstrualFlow","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"menstruation-flow","display":"Menstruation flow","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"menstrual-cycle-start","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"cycle-start","display":"Cycle start","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-menstrual-cycle-start"}]}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierMenstrualFlow"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zOQPZidTQvTfQKlYbhtjlfByibOVb39p77pRY-BIgRs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:i2VZaK7j7kjlmoihuJaK8_l9eGPvDFPEdHfePQSIu_8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-menstruation-flow","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"medium","display":"Medium","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-menstruation-flow"},{"code":"medium","display":"Medium","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-vaginal-bleeding"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierMenstrualFlow/4","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMenstrualCycleStart":{"boolean":true},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMenstrualFlow","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"menstruation-flow","display":"Menstruation flow","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"menstrual-cycle-start","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"cycle-start","display":"Cycle start","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-menstrual-cycle-start"}]}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierMenstrualFlow"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zOQPZidTQvTfQKlYbhtjlfByibOVb39p77pRY-BIgRs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:i2VZaK7j7kjlmoihuJaK8_l9eGPvDFPEdHfePQSIu_8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-menstruation-flow","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"heavy","display":"Heavy","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-menstruation-flow"},{"code":"heavy","display":"Heavy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-vaginal-bleeding"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierMenstrualFlow/5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMenstrualCycleStart":{"boolean":true},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMenstrualFlow","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"menstruation-flow","display":"Menstruation flow","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"menstrual-cycle-start","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"cycle-start","display":"Cycle start","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-menstrual-cycle-start"}]}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierMenstrualFlow"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zOQPZidTQvTfQKlYbhtjlfByibOVb39p77pRY-BIgRs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:i2VZaK7j7kjlmoihuJaK8_l9eGPvDFPEdHfePQSIu_8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-menstruation-flow","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"none","display":"None","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-menstruation-flow"},{"code":"none","display":"None","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-vaginal-bleeding"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierMenstrualFlow/6","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMenstrualCycleStart":{"boolean":true},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMenstrualFlow","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.menstrualFlow, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMenstrualFlow/7","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMenstrualCycleStart":{"boolean":true},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMenstrualFlow","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.menstrualFlow, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMenstrualFlow/8","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMenstrualCycleStart":{"boolean":true},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMenstrualFlow","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.menstrualFlow, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMindfulSession/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMindfulSession","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.mindfulSession, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMindfulSession/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMindfulSession","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"mindfulness-session-duration","display":"Mindfulness session duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierMindfulSession"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Wby_ilnn7V7N4-FEzyirDgKfqmzMcEO_1ZGxlv4_qvo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:S8i6GwVGbrJCBfgPnQHMuAoTXERMdUkRw1CoDk1XaMc"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-mindfulness-session","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"min","system":"http://unitsofmeasure.org","unit":"min","value":1}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierMindfulSession/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMindfulSession","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.mindfulSession, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMindfulSession/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMindfulSession","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.mindfulSession, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(2))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMindfulSession/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMindfulSession","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.mindfulSession, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(3))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMindfulSession/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMindfulSession","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.mindfulSession, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMindfulSession/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMindfulSession","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.mindfulSession, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMindfulSession/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMindfulSession","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.mindfulSession, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMindfulSession/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMindfulSession","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.mindfulSession, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMindfulSession/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMindfulSession","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.mindfulSession, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMoodChanges/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMoodChanges","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.moodChanges, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMoodChanges/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMoodChanges","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-mood-changes","display":"Mood changes","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierMoodChanges"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NBNAKTsQtHX0FMegg0-D_9OL-PdVmWJDNJypKkRGFXs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:aIqMDecpOwP_FBeQbulkSc9T9Jkrq3k5LJHfSbfo3kI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-mood-changes"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"present","display":"Present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-presence"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierMoodChanges/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMoodChanges","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-mood-changes","display":"Mood changes","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierMoodChanges"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NBNAKTsQtHX0FMegg0-D_9OL-PdVmWJDNJypKkRGFXs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:aIqMDecpOwP_FBeQbulkSc9T9Jkrq3k5LJHfSbfo3kI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-mood-changes"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-presence"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierMoodChanges/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMoodChanges","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.moodChanges, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(2))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMoodChanges/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMoodChanges","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.moodChanges, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(3))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMoodChanges/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMoodChanges","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.moodChanges, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMoodChanges/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMoodChanges","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.moodChanges, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMoodChanges/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMoodChanges","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.moodChanges, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMoodChanges/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMoodChanges","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.moodChanges, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierMoodChanges/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMoodChanges","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.moodChanges, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierNausea/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierNausea","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.nausea, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierNausea/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierNausea","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"81660-3","display":"Nausea [Presence]","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierNausea"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7yr3ClT5TA0yDyyVOC1R123ZbxOVazt0GrbRs_XPNHg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:g3jwvyODEW0zH-DhOE4PBsPHPe7LT6CQLIjIygLsTpI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-nausea"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierNausea/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierNausea","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"81660-3","display":"Nausea [Presence]","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierNausea"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7yr3ClT5TA0yDyyVOC1R123ZbxOVazt0GrbRs_XPNHg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:g3jwvyODEW0zH-DhOE4PBsPHPe7LT6CQLIjIygLsTpI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-nausea"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierNausea/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierNausea","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"81660-3","display":"Nausea [Presence]","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierNausea"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7yr3ClT5TA0yDyyVOC1R123ZbxOVazt0GrbRs_XPNHg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:g3jwvyODEW0zH-DhOE4PBsPHPe7LT6CQLIjIygLsTpI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-nausea"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierNausea/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierNausea","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"81660-3","display":"Nausea [Presence]","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierNausea"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7yr3ClT5TA0yDyyVOC1R123ZbxOVazt0GrbRs_XPNHg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:g3jwvyODEW0zH-DhOE4PBsPHPe7LT6CQLIjIygLsTpI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-nausea"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierNausea/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierNausea","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"81660-3","display":"Nausea [Presence]","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierNausea"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7yr3ClT5TA0yDyyVOC1R123ZbxOVazt0GrbRs_XPNHg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:g3jwvyODEW0zH-DhOE4PBsPHPe7LT6CQLIjIygLsTpI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-nausea"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierNausea/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierNausea","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.nausea, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierNausea/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierNausea","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.nausea, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierNausea/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierNausea","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.nausea, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierNausea/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierNausea","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.nausea, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierNightSweats/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierNightSweats","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.nightSweats, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierNightSweats/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierNightSweats","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-night-sweats","display":"Night sweats","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierNightSweats"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:lvTXdpCEjr0Vbf_qq-seOjSJKszl05ltnm1Barfz4oo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vfR8UJhGBYHDx4VVA4HKdsLDPD606Fu0TSa34GWy7cg"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-night-sweats"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierNightSweats/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierNightSweats","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-night-sweats","display":"Night sweats","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierNightSweats"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:lvTXdpCEjr0Vbf_qq-seOjSJKszl05ltnm1Barfz4oo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vfR8UJhGBYHDx4VVA4HKdsLDPD606Fu0TSa34GWy7cg"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-night-sweats"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierNightSweats/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierNightSweats","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-night-sweats","display":"Night sweats","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierNightSweats"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:lvTXdpCEjr0Vbf_qq-seOjSJKszl05ltnm1Barfz4oo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vfR8UJhGBYHDx4VVA4HKdsLDPD606Fu0TSa34GWy7cg"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-night-sweats"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierNightSweats/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierNightSweats","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-night-sweats","display":"Night sweats","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierNightSweats"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:lvTXdpCEjr0Vbf_qq-seOjSJKszl05ltnm1Barfz4oo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vfR8UJhGBYHDx4VVA4HKdsLDPD606Fu0TSa34GWy7cg"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-night-sweats"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierNightSweats/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierNightSweats","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-night-sweats","display":"Night sweats","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierNightSweats"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:lvTXdpCEjr0Vbf_qq-seOjSJKszl05ltnm1Barfz4oo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vfR8UJhGBYHDx4VVA4HKdsLDPD606Fu0TSa34GWy7cg"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-night-sweats"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierNightSweats/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierNightSweats","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.nightSweats, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierNightSweats/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierNightSweats","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.nightSweats, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierNightSweats/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierNightSweats","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.nightSweats, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierNightSweats/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierNightSweats","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.nightSweats, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierOvulationTestResult/-1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierOvulationTestResult","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.ovulationTestResult, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierOvulationTestResult/0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierOvulationTestResult","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.ovulationTestResult, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(0))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierOvulationTestResult/1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierOvulationTestResult","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"ovulation-test-result","display":"Ovulation test result","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierOvulationTestResult"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ymBGAC1iacD6HYb0RCXYFklYZJ6WzUYZL5q2beLzGnM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:o2pCLBZ7cGa3sQSKUT0OhObihGQQh7uaFf1fdghr9Js"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-ovulation-test-result","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"negative","display":"Negative","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-ovulation-test-result"},{"code":"negative","display":"Negative","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ovulation-test-result"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierOvulationTestResult/2","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierOvulationTestResult","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"ovulation-test-result","display":"Ovulation test result","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierOvulationTestResult"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ymBGAC1iacD6HYb0RCXYFklYZJ6WzUYZL5q2beLzGnM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:o2pCLBZ7cGa3sQSKUT0OhObihGQQh7uaFf1fdghr9Js"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-ovulation-test-result","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"luteinizing-hormone-surge","display":"Luteinizing hormone surge","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-ovulation-test-result"},{"code":"luteinizingHormoneSurge","display":"Luteinizing hormone surge","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ovulation-test-result"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierOvulationTestResult/3","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierOvulationTestResult","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"ovulation-test-result","display":"Ovulation test result","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierOvulationTestResult"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ymBGAC1iacD6HYb0RCXYFklYZJ6WzUYZL5q2beLzGnM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:o2pCLBZ7cGa3sQSKUT0OhObihGQQh7uaFf1fdghr9Js"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-ovulation-test-result","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"indeterminate","display":"Indeterminate","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-ovulation-test-result"},{"code":"indeterminate","display":"Indeterminate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ovulation-test-result"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierOvulationTestResult/4","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierOvulationTestResult","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"ovulation-test-result","display":"Ovulation test result","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierOvulationTestResult"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ymBGAC1iacD6HYb0RCXYFklYZJ6WzUYZL5q2beLzGnM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:o2pCLBZ7cGa3sQSKUT0OhObihGQQh7uaFf1fdghr9Js"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-ovulation-test-result","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"high-fertility","display":"High fertility","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-ovulation-test-result"},{"code":"estrogenSurge","display":"Estrogen surge","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ovulation-test-result"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierOvulationTestResult/5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierOvulationTestResult","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.ovulationTestResult, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierOvulationTestResult/6","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierOvulationTestResult","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.ovulationTestResult, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierOvulationTestResult/7","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierOvulationTestResult","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.ovulationTestResult, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierOvulationTestResult/8","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierOvulationTestResult","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.ovulationTestResult, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPelvicPain/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPelvicPain","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pelvicPain, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPelvicPain/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPelvicPain","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-pelvic-pain","display":"Pelvic pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierPelvicPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:214hgJdLS3mCJ5bzYgODB-vxcNtm5nTDmsPJUP2Ziyk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_TJexnGlS9w-Aj3SwYI5JJ0XbpllcExCAX55YojTkBw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-pelvic-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierPelvicPain/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPelvicPain","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-pelvic-pain","display":"Pelvic pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierPelvicPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:214hgJdLS3mCJ5bzYgODB-vxcNtm5nTDmsPJUP2Ziyk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_TJexnGlS9w-Aj3SwYI5JJ0XbpllcExCAX55YojTkBw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-pelvic-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierPelvicPain/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPelvicPain","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-pelvic-pain","display":"Pelvic pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierPelvicPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:214hgJdLS3mCJ5bzYgODB-vxcNtm5nTDmsPJUP2Ziyk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_TJexnGlS9w-Aj3SwYI5JJ0XbpllcExCAX55YojTkBw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-pelvic-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierPelvicPain/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPelvicPain","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-pelvic-pain","display":"Pelvic pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierPelvicPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:214hgJdLS3mCJ5bzYgODB-vxcNtm5nTDmsPJUP2Ziyk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_TJexnGlS9w-Aj3SwYI5JJ0XbpllcExCAX55YojTkBw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-pelvic-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierPelvicPain/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPelvicPain","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-pelvic-pain","display":"Pelvic pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierPelvicPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:214hgJdLS3mCJ5bzYgODB-vxcNtm5nTDmsPJUP2Ziyk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_TJexnGlS9w-Aj3SwYI5JJ0XbpllcExCAX55YojTkBw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-pelvic-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierPelvicPain/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPelvicPain","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pelvicPain, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPelvicPain/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPelvicPain","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pelvicPain, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPelvicPain/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPelvicPain","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pelvicPain, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPelvicPain/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPelvicPain","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pelvicPain, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPersistentIntermenstrualBleeding/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPersistentIntermenstrualBleeding","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.persistentIntermenstrualBleeding, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPersistentIntermenstrualBleeding/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPersistentIntermenstrualBleeding","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"persistent-intermenstrual-bleeding","display":"Persistent intermenstrual bleeding","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierPersistentIntermenstrualBleeding"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:CiAluADeDEnbK53sK8It7Xo4gxrgh6uUex44pvhGfBM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:S-TPyick34TJ0gbuh2lKlGA7DCqfWdoNL4uLfd1Ijp0"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-persistent-intermenstrual-bleeding"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-persistent-intermenstrual-bleeding"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierPersistentIntermenstrualBleeding/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPersistentIntermenstrualBleeding","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.persistentIntermenstrualBleeding, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPersistentIntermenstrualBleeding/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPersistentIntermenstrualBleeding","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.persistentIntermenstrualBleeding, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(2))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPersistentIntermenstrualBleeding/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPersistentIntermenstrualBleeding","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.persistentIntermenstrualBleeding, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(3))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPersistentIntermenstrualBleeding/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPersistentIntermenstrualBleeding","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.persistentIntermenstrualBleeding, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPersistentIntermenstrualBleeding/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPersistentIntermenstrualBleeding","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.persistentIntermenstrualBleeding, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPersistentIntermenstrualBleeding/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPersistentIntermenstrualBleeding","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.persistentIntermenstrualBleeding, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPersistentIntermenstrualBleeding/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPersistentIntermenstrualBleeding","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.persistentIntermenstrualBleeding, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPersistentIntermenstrualBleeding/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPersistentIntermenstrualBleeding","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.persistentIntermenstrualBleeding, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPregnancy/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPregnancy","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pregnancy, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPregnancy/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPregnancy","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"82810-3","display":"Pregnancy status","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierPregnancy"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jDJoTXGJHV0r60Na8dryt5ia-55xPoHTrxn04ZLZfUY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wop6SpzrLMNc40CAtdA2yCAM9wtC1nu79i1Oiw8AmVw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-pregnancy-status"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"pregnant","display":"Pregnant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-pregnancy-status"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierPregnancy/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPregnancy","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pregnancy, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPregnancy/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPregnancy","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pregnancy, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(2))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPregnancy/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPregnancy","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pregnancy, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(3))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPregnancy/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPregnancy","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pregnancy, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPregnancy/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPregnancy","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pregnancy, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPregnancy/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPregnancy","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pregnancy, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPregnancy/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPregnancy","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pregnancy, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPregnancy/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPregnancy","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pregnancy, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPregnancyTestResult/-1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPregnancyTestResult","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pregnancyTestResult, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPregnancyTestResult/0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPregnancyTestResult","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pregnancyTestResult, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(0))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPregnancyTestResult/1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPregnancyTestResult","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"2106-3","display":"Choriogonadotropin [Presence] in Urine","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierPregnancyTestResult"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:X548V5-DuUh_mEZYzYTgXev-dig_12Vk5vj_6PXNhRo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vYxjvXi5DUn-eQ-MebFoXAdYLBQE_LKyWwDXv7PJruk"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-pregnancy-test-result"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"negative","display":"Negative","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-pregnancy-test-result"},{"code":"negative","display":"Negative","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-test-result"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierPregnancyTestResult/2","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPregnancyTestResult","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"2106-3","display":"Choriogonadotropin [Presence] in Urine","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierPregnancyTestResult"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:X548V5-DuUh_mEZYzYTgXev-dig_12Vk5vj_6PXNhRo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vYxjvXi5DUn-eQ-MebFoXAdYLBQE_LKyWwDXv7PJruk"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-pregnancy-test-result"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"positive","display":"Positive","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-pregnancy-test-result"},{"code":"positive","display":"Positive","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-test-result"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierPregnancyTestResult/3","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPregnancyTestResult","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"2106-3","display":"Choriogonadotropin [Presence] in Urine","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierPregnancyTestResult"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:X548V5-DuUh_mEZYzYTgXev-dig_12Vk5vj_6PXNhRo"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vYxjvXi5DUn-eQ-MebFoXAdYLBQE_LKyWwDXv7PJruk"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-pregnancy-test-result"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"indeterminate","display":"Indeterminate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-pregnancy-test-result"},{"code":"indeterminate","display":"Indeterminate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-test-result"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierPregnancyTestResult/4","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPregnancyTestResult","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pregnancyTestResult, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPregnancyTestResult/5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPregnancyTestResult","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pregnancyTestResult, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPregnancyTestResult/6","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPregnancyTestResult","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pregnancyTestResult, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPregnancyTestResult/7","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPregnancyTestResult","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pregnancyTestResult, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierPregnancyTestResult/8","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierPregnancyTestResult","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.pregnancyTestResult, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierProgesteroneTestResult/-1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierProgesteroneTestResult","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.progesteroneTestResult, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierProgesteroneTestResult/0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierProgesteroneTestResult","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.progesteroneTestResult, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(0))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierProgesteroneTestResult/1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierProgesteroneTestResult","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"progesterone-test-result","display":"Progesterone (PdG) test result","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierProgesteroneTestResult"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:DcEBmE8IA9pMub96jphwRm-9IM7MeIrT_eRgcAH6Rxg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AMqSrapPTfID_6OrmSYl0nmFqAYF2J0mMsZrpGUF5xY"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-progesterone-test-result"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"negative","display":"Negative","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-progesterone-test-result"},{"code":"negative","display":"Negative","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-test-result"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierProgesteroneTestResult/2","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierProgesteroneTestResult","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"progesterone-test-result","display":"Progesterone (PdG) test result","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierProgesteroneTestResult"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:DcEBmE8IA9pMub96jphwRm-9IM7MeIrT_eRgcAH6Rxg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AMqSrapPTfID_6OrmSYl0nmFqAYF2J0mMsZrpGUF5xY"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-progesterone-test-result"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"positive","display":"Positive","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-progesterone-test-result"},{"code":"positive","display":"Positive","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-test-result"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierProgesteroneTestResult/3","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierProgesteroneTestResult","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"progesterone-test-result","display":"Progesterone (PdG) test result","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierProgesteroneTestResult"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:DcEBmE8IA9pMub96jphwRm-9IM7MeIrT_eRgcAH6Rxg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AMqSrapPTfID_6OrmSYl0nmFqAYF2J0mMsZrpGUF5xY"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-progesterone-test-result"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"indeterminate","display":"Indeterminate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-progesterone-test-result"},{"code":"indeterminate","display":"Indeterminate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-test-result"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierProgesteroneTestResult/4","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierProgesteroneTestResult","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.progesteroneTestResult, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierProgesteroneTestResult/5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierProgesteroneTestResult","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.progesteroneTestResult, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierProgesteroneTestResult/6","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierProgesteroneTestResult","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.progesteroneTestResult, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierProgesteroneTestResult/7","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierProgesteroneTestResult","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.progesteroneTestResult, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierProgesteroneTestResult/8","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierProgesteroneTestResult","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.progesteroneTestResult, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierProlongedMenstrualPeriods/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierProlongedMenstrualPeriods","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.prolongedMenstrualPeriods, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierProlongedMenstrualPeriods/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierProlongedMenstrualPeriods","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"prolonged-menstrual-periods","display":"Prolonged menstrual periods","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierProlongedMenstrualPeriods"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:kaMY9VCKPihmAWmoczs2kcq30Gv4T12t7Sj5uOm3LeM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:oHFIvU-qnJi5UdOTls1G7w1GqkMl7ScizkKJ8lAM2dw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-prolonged-menstrual-periods"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-prolonged-menstrual-periods"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierProlongedMenstrualPeriods/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierProlongedMenstrualPeriods","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.prolongedMenstrualPeriods, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierProlongedMenstrualPeriods/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierProlongedMenstrualPeriods","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.prolongedMenstrualPeriods, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(2))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierProlongedMenstrualPeriods/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierProlongedMenstrualPeriods","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.prolongedMenstrualPeriods, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(3))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierProlongedMenstrualPeriods/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierProlongedMenstrualPeriods","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.prolongedMenstrualPeriods, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierProlongedMenstrualPeriods/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierProlongedMenstrualPeriods","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.prolongedMenstrualPeriods, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierProlongedMenstrualPeriods/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierProlongedMenstrualPeriods","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.prolongedMenstrualPeriods, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierProlongedMenstrualPeriods/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierProlongedMenstrualPeriods","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.prolongedMenstrualPeriods, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierProlongedMenstrualPeriods/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierProlongedMenstrualPeriods","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.prolongedMenstrualPeriods, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.rapidPoundingOrFlutteringHeartbeat, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-rapid-pounding-or-fluttering-heartbeat","display":"Rapid, pounding, or fluttering heartbeat","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2vwSz6V380V8-coMInLmNhIp5hhDgKdnWddYJ1GFS-k"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:TZv0OK9uHuaqb95K1HJLS_Rq7iio7lIpyjFw1hlazTQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-rapid-pounding-or-fluttering-heartbeat"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-rapid-pounding-or-fluttering-heartbeat","display":"Rapid, pounding, or fluttering heartbeat","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2vwSz6V380V8-coMInLmNhIp5hhDgKdnWddYJ1GFS-k"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:TZv0OK9uHuaqb95K1HJLS_Rq7iio7lIpyjFw1hlazTQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-rapid-pounding-or-fluttering-heartbeat"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-rapid-pounding-or-fluttering-heartbeat","display":"Rapid, pounding, or fluttering heartbeat","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2vwSz6V380V8-coMInLmNhIp5hhDgKdnWddYJ1GFS-k"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:TZv0OK9uHuaqb95K1HJLS_Rq7iio7lIpyjFw1hlazTQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-rapid-pounding-or-fluttering-heartbeat"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-rapid-pounding-or-fluttering-heartbeat","display":"Rapid, pounding, or fluttering heartbeat","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2vwSz6V380V8-coMInLmNhIp5hhDgKdnWddYJ1GFS-k"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:TZv0OK9uHuaqb95K1HJLS_Rq7iio7lIpyjFw1hlazTQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-rapid-pounding-or-fluttering-heartbeat"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-rapid-pounding-or-fluttering-heartbeat","display":"Rapid, pounding, or fluttering heartbeat","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2vwSz6V380V8-coMInLmNhIp5hhDgKdnWddYJ1GFS-k"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:TZv0OK9uHuaqb95K1HJLS_Rq7iio7lIpyjFw1hlazTQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-rapid-pounding-or-fluttering-heartbeat"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.rapidPoundingOrFlutteringHeartbeat, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.rapidPoundingOrFlutteringHeartbeat, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.rapidPoundingOrFlutteringHeartbeat, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.rapidPoundingOrFlutteringHeartbeat, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierRunnyNose/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierRunnyNose","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.runnyNose, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierRunnyNose/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierRunnyNose","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-runny-nose","display":"Runny nose","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierRunnyNose"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AzHKkaR6hbtA4y9mEjiYIaCIU2uStuq5UHAJxGtLgj4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MsEGB8I5v7viO6XMQuUcHZzLQ7K7ROKaJ2aU4eAK16Q"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-runny-nose"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierRunnyNose/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierRunnyNose","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-runny-nose","display":"Runny nose","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierRunnyNose"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AzHKkaR6hbtA4y9mEjiYIaCIU2uStuq5UHAJxGtLgj4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MsEGB8I5v7viO6XMQuUcHZzLQ7K7ROKaJ2aU4eAK16Q"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-runny-nose"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierRunnyNose/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierRunnyNose","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-runny-nose","display":"Runny nose","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierRunnyNose"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AzHKkaR6hbtA4y9mEjiYIaCIU2uStuq5UHAJxGtLgj4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MsEGB8I5v7viO6XMQuUcHZzLQ7K7ROKaJ2aU4eAK16Q"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-runny-nose"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierRunnyNose/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierRunnyNose","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-runny-nose","display":"Runny nose","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierRunnyNose"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AzHKkaR6hbtA4y9mEjiYIaCIU2uStuq5UHAJxGtLgj4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MsEGB8I5v7viO6XMQuUcHZzLQ7K7ROKaJ2aU4eAK16Q"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-runny-nose"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierRunnyNose/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierRunnyNose","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-runny-nose","display":"Runny nose","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierRunnyNose"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:AzHKkaR6hbtA4y9mEjiYIaCIU2uStuq5UHAJxGtLgj4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MsEGB8I5v7viO6XMQuUcHZzLQ7K7ROKaJ2aU4eAK16Q"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-runny-nose"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierRunnyNose/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierRunnyNose","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.runnyNose, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierRunnyNose/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierRunnyNose","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.runnyNose, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierRunnyNose/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierRunnyNose","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.runnyNose, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierRunnyNose/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierRunnyNose","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.runnyNose, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSexualActivity/-1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSexualActivity","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sexualActivity, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSexualActivity/0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSexualActivity","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"sexual-activity","display":"Sexual activity","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSexualActivity"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:lPEB9lIVwzwL_XQhftEDx4-95fgZuyOhCg1cfxowq3I"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:FI4pGDsSw5sWnaPieuPeuqDvYzsl-wNnSQ_onDCux1I"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-sexual-activity","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"unknown","display":"Unknown","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-sexual-activity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSexualActivity/1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSexualActivity","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sexualActivity, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSexualActivity/2","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSexualActivity","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sexualActivity, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(2))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSexualActivity/3","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSexualActivity","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sexualActivity, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(3))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSexualActivity/4","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSexualActivity","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sexualActivity, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSexualActivity/5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSexualActivity","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sexualActivity, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSexualActivity/6","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSexualActivity","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sexualActivity, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSexualActivity/7","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSexualActivity","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sexualActivity, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSexualActivity/8","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSexualActivity","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sexualActivity, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierShortnessOfBreath/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierShortnessOfBreath","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.shortnessOfBreath, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierShortnessOfBreath/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierShortnessOfBreath","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-shortness-of-breath","display":"Shortness of breath","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierShortnessOfBreath"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:QC2jREacoCscDfDAOSoyQkkCn-B72ndho6Kah4Lhjjs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_1YBOamNGfGxjJQP2uskQ4GwtxUzZG7EPQeEmdZqB3g"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-shortness-of-breath"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierShortnessOfBreath/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierShortnessOfBreath","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-shortness-of-breath","display":"Shortness of breath","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierShortnessOfBreath"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:QC2jREacoCscDfDAOSoyQkkCn-B72ndho6Kah4Lhjjs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_1YBOamNGfGxjJQP2uskQ4GwtxUzZG7EPQeEmdZqB3g"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-shortness-of-breath"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierShortnessOfBreath/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierShortnessOfBreath","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-shortness-of-breath","display":"Shortness of breath","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierShortnessOfBreath"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:QC2jREacoCscDfDAOSoyQkkCn-B72ndho6Kah4Lhjjs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_1YBOamNGfGxjJQP2uskQ4GwtxUzZG7EPQeEmdZqB3g"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-shortness-of-breath"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierShortnessOfBreath/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierShortnessOfBreath","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-shortness-of-breath","display":"Shortness of breath","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierShortnessOfBreath"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:QC2jREacoCscDfDAOSoyQkkCn-B72ndho6Kah4Lhjjs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_1YBOamNGfGxjJQP2uskQ4GwtxUzZG7EPQeEmdZqB3g"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-shortness-of-breath"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierShortnessOfBreath/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierShortnessOfBreath","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-shortness-of-breath","display":"Shortness of breath","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierShortnessOfBreath"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:QC2jREacoCscDfDAOSoyQkkCn-B72ndho6Kah4Lhjjs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_1YBOamNGfGxjJQP2uskQ4GwtxUzZG7EPQeEmdZqB3g"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-shortness-of-breath"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierShortnessOfBreath/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierShortnessOfBreath","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.shortnessOfBreath, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierShortnessOfBreath/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierShortnessOfBreath","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.shortnessOfBreath, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierShortnessOfBreath/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierShortnessOfBreath","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.shortnessOfBreath, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierShortnessOfBreath/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierShortnessOfBreath","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.shortnessOfBreath, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSinusCongestion/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSinusCongestion","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sinusCongestion, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSinusCongestion/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSinusCongestion","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-sinus-congestion","display":"Sinus congestion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSinusCongestion"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ceLZl4v3c3UANWrtw28Lx77cCtI_zsqWuX3USQdg6GY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:USTe5Tfsfg4CzDeKERk6FwFGZhJhV6NsJgmD3aMin6Q"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-sinus-congestion"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSinusCongestion/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSinusCongestion","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-sinus-congestion","display":"Sinus congestion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSinusCongestion"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ceLZl4v3c3UANWrtw28Lx77cCtI_zsqWuX3USQdg6GY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:USTe5Tfsfg4CzDeKERk6FwFGZhJhV6NsJgmD3aMin6Q"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-sinus-congestion"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSinusCongestion/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSinusCongestion","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-sinus-congestion","display":"Sinus congestion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSinusCongestion"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ceLZl4v3c3UANWrtw28Lx77cCtI_zsqWuX3USQdg6GY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:USTe5Tfsfg4CzDeKERk6FwFGZhJhV6NsJgmD3aMin6Q"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-sinus-congestion"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSinusCongestion/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSinusCongestion","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-sinus-congestion","display":"Sinus congestion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSinusCongestion"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ceLZl4v3c3UANWrtw28Lx77cCtI_zsqWuX3USQdg6GY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:USTe5Tfsfg4CzDeKERk6FwFGZhJhV6NsJgmD3aMin6Q"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-sinus-congestion"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSinusCongestion/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSinusCongestion","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-sinus-congestion","display":"Sinus congestion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSinusCongestion"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ceLZl4v3c3UANWrtw28Lx77cCtI_zsqWuX3USQdg6GY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:USTe5Tfsfg4CzDeKERk6FwFGZhJhV6NsJgmD3aMin6Q"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-sinus-congestion"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSinusCongestion/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSinusCongestion","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sinusCongestion, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSinusCongestion/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSinusCongestion","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sinusCongestion, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSinusCongestion/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSinusCongestion","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sinusCongestion, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSinusCongestion/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSinusCongestion","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sinusCongestion, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSkippedHeartbeat/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSkippedHeartbeat","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.skippedHeartbeat, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSkippedHeartbeat/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSkippedHeartbeat","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-skipped-heartbeat","display":"Skipped heartbeat","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSkippedHeartbeat"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dNHQUU-JDst03ojH1RSeV2JUAWqlFIYBFPFmY3K4jns"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dG58gX13PHrqyvI0kkJgM73PbiUUpNgJvndrZFkraNE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-skipped-heartbeat"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSkippedHeartbeat/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSkippedHeartbeat","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-skipped-heartbeat","display":"Skipped heartbeat","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSkippedHeartbeat"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dNHQUU-JDst03ojH1RSeV2JUAWqlFIYBFPFmY3K4jns"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dG58gX13PHrqyvI0kkJgM73PbiUUpNgJvndrZFkraNE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-skipped-heartbeat"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSkippedHeartbeat/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSkippedHeartbeat","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-skipped-heartbeat","display":"Skipped heartbeat","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSkippedHeartbeat"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dNHQUU-JDst03ojH1RSeV2JUAWqlFIYBFPFmY3K4jns"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dG58gX13PHrqyvI0kkJgM73PbiUUpNgJvndrZFkraNE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-skipped-heartbeat"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSkippedHeartbeat/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSkippedHeartbeat","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-skipped-heartbeat","display":"Skipped heartbeat","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSkippedHeartbeat"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dNHQUU-JDst03ojH1RSeV2JUAWqlFIYBFPFmY3K4jns"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dG58gX13PHrqyvI0kkJgM73PbiUUpNgJvndrZFkraNE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-skipped-heartbeat"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSkippedHeartbeat/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSkippedHeartbeat","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-skipped-heartbeat","display":"Skipped heartbeat","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSkippedHeartbeat"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dNHQUU-JDst03ojH1RSeV2JUAWqlFIYBFPFmY3K4jns"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:dG58gX13PHrqyvI0kkJgM73PbiUUpNgJvndrZFkraNE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-skipped-heartbeat"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSkippedHeartbeat/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSkippedHeartbeat","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.skippedHeartbeat, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSkippedHeartbeat/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSkippedHeartbeat","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.skippedHeartbeat, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSkippedHeartbeat/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSkippedHeartbeat","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.skippedHeartbeat, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSkippedHeartbeat/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSkippedHeartbeat","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.skippedHeartbeat, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSleepAnalysis/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepAnalysis","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sleepAnalysis, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSleepAnalysis/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepAnalysis","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"sleep-stage","display":"Sleep stage","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSleepAnalysis"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jxMm8nPoiKKJaThST6pA0pho_YBqzjr8GngjJnD-BnQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:sQvdH5bt3Mi-S5ng5AsHsyg3sygBMl_XcztZi4V2STA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-sleep-stage","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"in-bed","display":"In bed","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-sleep-stage"},{"code":"inBed","display":"In bed","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-sleep-analysis"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSleepAnalysis/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepAnalysis","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"sleep-stage","display":"Sleep stage","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSleepAnalysis"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jxMm8nPoiKKJaThST6pA0pho_YBqzjr8GngjJnD-BnQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:sQvdH5bt3Mi-S5ng5AsHsyg3sygBMl_XcztZi4V2STA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-sleep-stage","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"asleep-unspecified","display":"Asleep, unspecified stage","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-sleep-stage"},{"code":"asleepUnspecified","display":"Asleep, unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-sleep-analysis"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSleepAnalysis/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepAnalysis","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"sleep-stage","display":"Sleep stage","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSleepAnalysis"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jxMm8nPoiKKJaThST6pA0pho_YBqzjr8GngjJnD-BnQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:sQvdH5bt3Mi-S5ng5AsHsyg3sygBMl_XcztZi4V2STA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-sleep-stage","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"awake","display":"Awake","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-sleep-stage"},{"code":"awake","display":"Awake","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-sleep-analysis"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSleepAnalysis/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepAnalysis","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"sleep-stage","display":"Sleep stage","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSleepAnalysis"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jxMm8nPoiKKJaThST6pA0pho_YBqzjr8GngjJnD-BnQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:sQvdH5bt3Mi-S5ng5AsHsyg3sygBMl_XcztZi4V2STA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-sleep-stage","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"light","display":"Light sleep","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-sleep-stage"},{"code":"asleepCore","display":"Asleep, core","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-sleep-analysis"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSleepAnalysis/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepAnalysis","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"sleep-stage","display":"Sleep stage","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSleepAnalysis"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jxMm8nPoiKKJaThST6pA0pho_YBqzjr8GngjJnD-BnQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:sQvdH5bt3Mi-S5ng5AsHsyg3sygBMl_XcztZi4V2STA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-sleep-stage","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"deep","display":"Deep sleep","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-sleep-stage"},{"code":"asleepDeep","display":"Asleep, deep","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-sleep-analysis"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSleepAnalysis/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepAnalysis","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"sleep-stage","display":"Sleep stage","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSleepAnalysis"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jxMm8nPoiKKJaThST6pA0pho_YBqzjr8GngjJnD-BnQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:sQvdH5bt3Mi-S5ng5AsHsyg3sygBMl_XcztZi4V2STA"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-sleep-stage","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"rem","display":"REM sleep","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-sleep-stage"},{"code":"asleepREM","display":"Asleep, REM","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-sleep-analysis"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSleepAnalysis/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepAnalysis","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sleepAnalysis, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSleepAnalysis/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepAnalysis","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sleepAnalysis, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSleepAnalysis/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepAnalysis","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sleepAnalysis, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSleepApneaEvent/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepApneaEvent","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sleepApneaEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSleepApneaEvent/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepApneaEvent","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"sleep-apnea-notification","display":"Sleep Apnea Notification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSleepApneaEvent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:rGCo0r1OkpIQxHT3F-6F9jca-0X6LUuYZFZN2nAM_2g"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:w4avGeqB4nSza-deaqIzncwLu5LMzajWVP3m_uubjbE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-sleep-apnea-notification"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"occurred","display":"Occurred","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-sleep-apnea-notification"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSleepApneaEvent/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepApneaEvent","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sleepApneaEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSleepApneaEvent/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepApneaEvent","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sleepApneaEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(2))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSleepApneaEvent/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepApneaEvent","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sleepApneaEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(3))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSleepApneaEvent/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepApneaEvent","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sleepApneaEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSleepApneaEvent/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepApneaEvent","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sleepApneaEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSleepApneaEvent/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepApneaEvent","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sleepApneaEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSleepApneaEvent/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepApneaEvent","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sleepApneaEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSleepApneaEvent/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepApneaEvent","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sleepApneaEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSleepChanges/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepChanges","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sleepChanges, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSleepChanges/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepChanges","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-sleep-changes","display":"Sleep changes","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSleepChanges"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fX17irDpfRuCpfx7D7knovvsSbYIgvuS8hyqW_kxTK0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:B_A7yKPDpvp_ER8YO6GmG_xvTG4KeWihK35kRqb3XSE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-sleep-changes"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"present","display":"Present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-presence"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSleepChanges/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepChanges","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-sleep-changes","display":"Sleep changes","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSleepChanges"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:fX17irDpfRuCpfx7D7knovvsSbYIgvuS8hyqW_kxTK0"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:B_A7yKPDpvp_ER8YO6GmG_xvTG4KeWihK35kRqb3XSE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-sleep-changes"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-presence"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSleepChanges/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepChanges","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sleepChanges, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(2))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSleepChanges/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepChanges","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sleepChanges, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(3))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSleepChanges/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepChanges","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sleepChanges, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSleepChanges/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepChanges","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sleepChanges, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSleepChanges/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepChanges","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sleepChanges, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSleepChanges/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepChanges","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sleepChanges, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSleepChanges/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepChanges","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sleepChanges, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSoreThroat/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSoreThroat","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.soreThroat, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSoreThroat/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSoreThroat","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-sore-throat","display":"Sore throat","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSoreThroat"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:05BXaaBPHfPqkXWMHycwPwPfn-Y7N-DXN3lVo7Ol_yc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:hdrFcP70I1watCiWm1QT7b_i0NyvaNc6HCNWC5ETEfs"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-sore-throat"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSoreThroat/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSoreThroat","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-sore-throat","display":"Sore throat","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSoreThroat"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:05BXaaBPHfPqkXWMHycwPwPfn-Y7N-DXN3lVo7Ol_yc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:hdrFcP70I1watCiWm1QT7b_i0NyvaNc6HCNWC5ETEfs"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-sore-throat"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSoreThroat/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSoreThroat","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-sore-throat","display":"Sore throat","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSoreThroat"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:05BXaaBPHfPqkXWMHycwPwPfn-Y7N-DXN3lVo7Ol_yc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:hdrFcP70I1watCiWm1QT7b_i0NyvaNc6HCNWC5ETEfs"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-sore-throat"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSoreThroat/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSoreThroat","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-sore-throat","display":"Sore throat","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSoreThroat"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:05BXaaBPHfPqkXWMHycwPwPfn-Y7N-DXN3lVo7Ol_yc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:hdrFcP70I1watCiWm1QT7b_i0NyvaNc6HCNWC5ETEfs"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-sore-throat"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSoreThroat/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSoreThroat","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-sore-throat","display":"Sore throat","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSoreThroat"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:05BXaaBPHfPqkXWMHycwPwPfn-Y7N-DXN3lVo7Ol_yc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:hdrFcP70I1watCiWm1QT7b_i0NyvaNc6HCNWC5ETEfs"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-sore-throat"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierSoreThroat/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSoreThroat","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.soreThroat, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSoreThroat/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSoreThroat","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.soreThroat, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSoreThroat/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSoreThroat","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.soreThroat, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierSoreThroat/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSoreThroat","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.soreThroat, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierToothbrushingEvent/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierToothbrushingEvent","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.toothbrushingEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierToothbrushingEvent/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierToothbrushingEvent","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"toothbrushing-session","display":"Toothbrushing session","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierToothbrushingEvent"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:c6Eoc-c8tYg_7-X1zkb42LjuWE-XPk9-UsFS_kwfxgA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:l9x5fcO4lAHMq4FaVVsGjbJBNEioNnl5h9sCGNCaJPc"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-toothbrushing-session"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":60}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierToothbrushingEvent/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierToothbrushingEvent","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.toothbrushingEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierToothbrushingEvent/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierToothbrushingEvent","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.toothbrushingEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(2))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierToothbrushingEvent/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierToothbrushingEvent","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.toothbrushingEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(3))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierToothbrushingEvent/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierToothbrushingEvent","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.toothbrushingEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(4))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierToothbrushingEvent/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierToothbrushingEvent","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.toothbrushingEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierToothbrushingEvent/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierToothbrushingEvent","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.toothbrushingEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierToothbrushingEvent/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierToothbrushingEvent","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.toothbrushingEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierToothbrushingEvent/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierToothbrushingEvent","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.toothbrushingEvent, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierVaginalDryness/-1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierVaginalDryness","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.vaginalDryness, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierVaginalDryness/0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierVaginalDryness","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"vaginal-dryness","display":"Vaginal dryness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierVaginalDryness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YU3N5tLeZ3dO4QvuQKIgmF83GMlSfJtProEwG7fHD_w"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yTUVa_gXwzCKhXNyWNydsEdhivTwwTgtScyhTqziwHA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-vaginal-dryness"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierVaginalDryness/1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierVaginalDryness","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"vaginal-dryness","display":"Vaginal dryness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierVaginalDryness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YU3N5tLeZ3dO4QvuQKIgmF83GMlSfJtProEwG7fHD_w"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yTUVa_gXwzCKhXNyWNydsEdhivTwwTgtScyhTqziwHA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-vaginal-dryness"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierVaginalDryness/2","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierVaginalDryness","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"vaginal-dryness","display":"Vaginal dryness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierVaginalDryness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YU3N5tLeZ3dO4QvuQKIgmF83GMlSfJtProEwG7fHD_w"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yTUVa_gXwzCKhXNyWNydsEdhivTwwTgtScyhTqziwHA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-vaginal-dryness"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierVaginalDryness/3","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierVaginalDryness","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"vaginal-dryness","display":"Vaginal dryness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierVaginalDryness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YU3N5tLeZ3dO4QvuQKIgmF83GMlSfJtProEwG7fHD_w"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yTUVa_gXwzCKhXNyWNydsEdhivTwwTgtScyhTqziwHA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-vaginal-dryness"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierVaginalDryness/4","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierVaginalDryness","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"vaginal-dryness","display":"Vaginal dryness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierVaginalDryness"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:YU3N5tLeZ3dO4QvuQKIgmF83GMlSfJtProEwG7fHD_w"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yTUVa_gXwzCKhXNyWNydsEdhivTwwTgtScyhTqziwHA"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-vaginal-dryness"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierVaginalDryness/5","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierVaginalDryness","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.vaginalDryness, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierVaginalDryness/6","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierVaginalDryness","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.vaginalDryness, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierVaginalDryness/7","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierVaginalDryness","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.vaginalDryness, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierVaginalDryness/8","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierVaginalDryness","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.vaginalDryness, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierVomiting/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierVomiting","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.vomiting, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierVomiting/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierVomiting","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-vomiting","display":"Vomiting","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierVomiting"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NqAC9MA2c-UBw1YQu1ZEPX5JEhdmeVLoPVlGV8DNJx4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_MnLaPiGY7QV3fKzyxzSLFwQYD-7Ku5q541ip5eG7BM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-vomiting"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierVomiting/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierVomiting","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-vomiting","display":"Vomiting","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierVomiting"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NqAC9MA2c-UBw1YQu1ZEPX5JEhdmeVLoPVlGV8DNJx4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_MnLaPiGY7QV3fKzyxzSLFwQYD-7Ku5q541ip5eG7BM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-vomiting"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierVomiting/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierVomiting","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-vomiting","display":"Vomiting","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierVomiting"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NqAC9MA2c-UBw1YQu1ZEPX5JEhdmeVLoPVlGV8DNJx4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_MnLaPiGY7QV3fKzyxzSLFwQYD-7Ku5q541ip5eG7BM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-vomiting"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierVomiting/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierVomiting","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-vomiting","display":"Vomiting","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierVomiting"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NqAC9MA2c-UBw1YQu1ZEPX5JEhdmeVLoPVlGV8DNJx4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_MnLaPiGY7QV3fKzyxzSLFwQYD-7Ku5q541ip5eG7BM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-vomiting"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierVomiting/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierVomiting","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-vomiting","display":"Vomiting","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierVomiting"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:NqAC9MA2c-UBw1YQu1ZEPX5JEhdmeVLoPVlGV8DNJx4"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_MnLaPiGY7QV3fKzyxzSLFwQYD-7Ku5q541ip5eG7BM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-vomiting"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierVomiting/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierVomiting","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.vomiting, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierVomiting/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierVomiting","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.vomiting, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierVomiting/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierVomiting","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.vomiting, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierVomiting/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierVomiting","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.vomiting, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierWheezing/-1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierWheezing","value":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.wheezing, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(-1))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierWheezing/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierWheezing","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-wheezing","display":"Wheezing","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierWheezing"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0u28eMY8uX6bgO2OsPwz95TSTVFz2Ka08ktlYJnVYZk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:XwlM_8E6938ySrAdqN86k4kVGfIqtTo0nFcZWJ9GXrc"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-wheezing"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"present","display":"Present, severity unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"unspecified","display":"Unspecified","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierWheezing/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierWheezing","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-wheezing","display":"Wheezing","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierWheezing"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0u28eMY8uX6bgO2OsPwz95TSTVFz2Ka08ktlYJnVYZk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:XwlM_8E6938ySrAdqN86k4kVGfIqtTo0nFcZWJ9GXrc"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-wheezing"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"not-present","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"notPresent","display":"Not present","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierWheezing/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierWheezing","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-wheezing","display":"Wheezing","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierWheezing"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0u28eMY8uX6bgO2OsPwz95TSTVFz2Ka08ktlYJnVYZk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:XwlM_8E6938ySrAdqN86k4kVGfIqtTo0nFcZWJ9GXrc"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-wheezing"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierWheezing/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierWheezing","value":3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-wheezing","display":"Wheezing","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierWheezing"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0u28eMY8uX6bgO2OsPwz95TSTVFz2Ka08ktlYJnVYZk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:XwlM_8E6938ySrAdqN86k4kVGfIqtTo0nFcZWJ9GXrc"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-wheezing"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierWheezing/4","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierWheezing","value":4}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"symptom-wheezing","display":"Wheezing","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierWheezing"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0u28eMY8uX6bgO2OsPwz95TSTVFz2Ka08ktlYJnVYZk"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:XwlM_8E6938ySrAdqN86k4kVGfIqtTo0nFcZWJ9GXrc"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-wheezing"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"category/HKCategoryTypeIdentifierWheezing/5","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierWheezing","value":5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.wheezing, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(5))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierWheezing/6","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierWheezing","value":6}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.wheezing, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(6))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierWheezing/7","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierWheezing","value":7}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.wheezing, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(7))","location":"HKSample.value"}}} +{"id":"category/HKCategoryTypeIdentifierWheezing/8","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierWheezing","value":8}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.wheezing, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(8))","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/equal","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/interval-45s","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/reversed-45s","input":{"convert":{"source":{"context":"plain","end":1787005755,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/zone-none","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T22:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":["mobile-omission.source-offset@Observation.effectiveDateTime"]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/zone-invalid","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"Not/A-Time-Zone"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bodyMass, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.timeZone))","location":"HKSample.metadata[HKTimeZone]"}}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/zone-wrong-type","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"integer":42}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bodyMass, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.timeZone))","location":"HKSample.metadata[HKTimeZone]"}}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/zone-los-angeles","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/zone-kolkata","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"Asia/Kolkata"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"Asia/Kolkata"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-18T04:00:00+05:30","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/zone-kathmandu","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"Asia/Kathmandu"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"Asia/Kathmandu"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-18T04:15:00+05:45","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/zone-st-johns","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"America/St_Johns"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/St_Johns"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T20:00:00-02:30","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/zone-utc","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"UTC"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"GMT"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T22:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/repeated-hour-first/none","input":{"convert":{"source":{"context":"plain","end":1793521800,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":1793521800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-11-01T08:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":["mobile-omission.source-offset@Observation.effectiveDateTime"]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/repeated-hour-first/los-angeles","input":{"convert":{"source":{"context":"plain","end":1793521800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":1793521800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-11-01T01:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/repeated-hour-second/none","input":{"convert":{"source":{"context":"plain","end":1793525400,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":1793525400,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-11-01T09:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":["mobile-omission.source-offset@Observation.effectiveDateTime"]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/repeated-hour-second/los-angeles","input":{"convert":{"source":{"context":"plain","end":1793525400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":1793525400,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-11-01T01:30:00-08:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/lmt-1800/none","input":{"convert":{"source":{"context":"plain","end":-5364662400,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":-5364662400,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"1800-01-01T00:00:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":["mobile-omission.source-offset@Observation.effectiveDateTime"]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/lmt-1800/los-angeles","input":{"convert":{"source":{"context":"plain","end":-5364662400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":-5364662400,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bodyMass, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/fraction-250/none","input":{"convert":{"source":{"context":"plain","end":1787148600.25,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":1787148600.25,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-19T14:10:00.250Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":["mobile-omission.source-offset@Observation.effectiveDateTime"]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/fraction-250/los-angeles","input":{"convert":{"source":{"context":"plain","end":1787148600.25,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":1787148600.25,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-19T07:10:00.250-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/tie-even/none","input":{"convert":{"source":{"context":"plain","end":1787148600.0625,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":1787148600.0625,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-19T14:10:00.062Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":["mobile-omission.source-offset@Observation.effectiveDateTime"]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/tie-even/los-angeles","input":{"convert":{"source":{"context":"plain","end":1787148600.0625,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":1787148600.0625,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-19T07:10:00.062-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/tie-odd/none","input":{"convert":{"source":{"context":"plain","end":1787148600.1875,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":1787148600.1875,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-19T14:10:00.188Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":["mobile-omission.source-offset@Observation.effectiveDateTime"]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/tie-odd/los-angeles","input":{"convert":{"source":{"context":"plain","end":1787148600.1875,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":1787148600.1875,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-19T07:10:00.188-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/year-9999/none","input":{"convert":{"source":{"context":"plain","end":253402300799,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":253402300799,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"9999-12-31T23:59:59Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":["mobile-omission.source-offset@Observation.effectiveDateTime"]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/year-9999/los-angeles","input":{"convert":{"source":{"context":"plain","end":253402300799,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":253402300799,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"9999-12-31T15:59:59-08:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/year-10000/none","input":{"convert":{"source":{"context":"plain","end":253402300800,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":253402300800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bodyMass, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/year-10000/los-angeles","input":{"convert":{"source":{"context":"plain","end":253402300800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":253402300800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"9999-12-31T16:00:00-08:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/pre-reform-1500/none","input":{"convert":{"source":{"context":"plain","end":-14831769600,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":-14831769600,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"1500-01-01T00:00:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":["mobile-omission.source-offset@Observation.effectiveDateTime"]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/pre-reform-1500/los-angeles","input":{"convert":{"source":{"context":"plain","end":-14831769600,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":-14831769600,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bodyMass, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/year-1/none","input":{"convert":{"source":{"context":"plain","end":-62135596800,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":-62135596800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"0001-01-01T00:00:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":["mobile-omission.source-offset@Observation.effectiveDateTime"]}]}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/year-1/los-angeles","input":{"convert":{"source":{"context":"plain","end":-62135596800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":-62135596800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bodyMass, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/year-0/none","input":{"convert":{"source":{"context":"plain","end":-62135596801,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":-62135596801,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bodyMass, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierBodyMass/year-0/los-angeles","input":{"convert":{"source":{"context":"plain","end":-62135596801,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":-62135596801,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bodyMass, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/equal","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/interval-45s","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/reversed-45s","input":{"convert":{"source":{"context":"plain","end":1787005755,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/zone-none","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T22:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":["mobile-omission.source-offset@Observation.effectiveDateTime"]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/zone-invalid","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"Not/A-Time-Zone"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.timeZone))","location":"HKSample.metadata[HKTimeZone]"}}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/zone-wrong-type","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"integer":42}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.timeZone))","location":"HKSample.metadata[HKTimeZone]"}}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/zone-los-angeles","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/zone-kolkata","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"Asia/Kolkata"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"Asia/Kolkata"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-18T04:00:00+05:30","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/zone-kathmandu","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"Asia/Kathmandu"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"Asia/Kathmandu"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-18T04:15:00+05:45","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/zone-st-johns","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"America/St_Johns"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/St_Johns"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T20:00:00-02:30","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/zone-utc","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"UTC"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"GMT"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T22:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/repeated-hour-first/none","input":{"convert":{"source":{"context":"plain","end":1793521800,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1793521800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-11-01T08:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":["mobile-omission.source-offset@Observation.effectiveDateTime"]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/repeated-hour-first/los-angeles","input":{"convert":{"source":{"context":"plain","end":1793521800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1793521800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-11-01T01:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/repeated-hour-second/none","input":{"convert":{"source":{"context":"plain","end":1793525400,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1793525400,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-11-01T09:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":["mobile-omission.source-offset@Observation.effectiveDateTime"]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/repeated-hour-second/los-angeles","input":{"convert":{"source":{"context":"plain","end":1793525400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1793525400,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-11-01T01:30:00-08:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/lmt-1800/none","input":{"convert":{"source":{"context":"plain","end":-5364662400,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":-5364662400,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"1800-01-01T00:00:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":["mobile-omission.source-offset@Observation.effectiveDateTime"]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/lmt-1800/los-angeles","input":{"convert":{"source":{"context":"plain","end":-5364662400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":-5364662400,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/fraction-250/none","input":{"convert":{"source":{"context":"plain","end":1787148600.25,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787148600.25,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-19T14:10:00.250Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":["mobile-omission.source-offset@Observation.effectiveDateTime"]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/fraction-250/los-angeles","input":{"convert":{"source":{"context":"plain","end":1787148600.25,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787148600.25,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-19T07:10:00.250-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/tie-even/none","input":{"convert":{"source":{"context":"plain","end":1787148600.0625,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787148600.0625,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-19T14:10:00.062Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":["mobile-omission.source-offset@Observation.effectiveDateTime"]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/tie-even/los-angeles","input":{"convert":{"source":{"context":"plain","end":1787148600.0625,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787148600.0625,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-19T07:10:00.062-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/tie-odd/none","input":{"convert":{"source":{"context":"plain","end":1787148600.1875,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787148600.1875,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-19T14:10:00.188Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":["mobile-omission.source-offset@Observation.effectiveDateTime"]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/tie-odd/los-angeles","input":{"convert":{"source":{"context":"plain","end":1787148600.1875,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787148600.1875,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-19T07:10:00.188-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/year-9999/none","input":{"convert":{"source":{"context":"plain","end":253402300799,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":253402300799,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"9999-12-31T23:59:59Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":["mobile-omission.source-offset@Observation.effectiveDateTime"]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/year-9999/los-angeles","input":{"convert":{"source":{"context":"plain","end":253402300799,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":253402300799,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"9999-12-31T15:59:59-08:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/year-10000/none","input":{"convert":{"source":{"context":"plain","end":253402300800,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":253402300800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/year-10000/los-angeles","input":{"convert":{"source":{"context":"plain","end":253402300800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":253402300800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"9999-12-31T16:00:00-08:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/pre-reform-1500/none","input":{"convert":{"source":{"context":"plain","end":-14831769600,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":-14831769600,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"1500-01-01T00:00:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":["mobile-omission.source-offset@Observation.effectiveDateTime"]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/pre-reform-1500/los-angeles","input":{"convert":{"source":{"context":"plain","end":-14831769600,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":-14831769600,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/year-1/none","input":{"convert":{"source":{"context":"plain","end":-62135596800,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":-62135596800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"0001-01-01T00:00:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":["mobile-omission.source-offset@Observation.effectiveDateTime"]}]}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/year-1/los-angeles","input":{"convert":{"source":{"context":"plain","end":-62135596800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":-62135596800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/year-0/none","input":{"convert":{"source":{"context":"plain","end":-62135596801,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":-62135596801,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierHeartRate/year-0/los-angeles","input":{"convert":{"source":{"context":"plain","end":-62135596801,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":-62135596801,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/equal","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":650}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/interval-45s","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:45-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":650}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/reversed-45s","input":{"convert":{"source":{"context":"plain","end":1787005755,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryEnergyConsumed, GroveHealthKitFHIR.HealthKitValueFailure.effectivePeriodInvalid)","location":"HKSample.startDate"}}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/zone-none","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"end":"2026-08-17T22:30:45Z","start":"2026-08-17T22:30:00Z"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":650}}],"warnings":["mobile-omission.source-offset@Observation.effectivePeriod.start","mobile-omission.source-offset@Observation.effectivePeriod.end"]}]}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/zone-invalid","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"Not/A-Time-Zone"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryEnergyConsumed, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.timeZone))","location":"HKSample.metadata[HKTimeZone]"}}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/zone-wrong-type","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"integer":42}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryEnergyConsumed, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.timeZone))","location":"HKSample.metadata[HKTimeZone]"}}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/zone-los-angeles","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:45-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":650}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/zone-kolkata","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"Asia/Kolkata"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"Asia/Kolkata"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"Asia/Kolkata"}]},"end":"2026-08-18T04:00:45+05:30","start":"2026-08-18T04:00:00+05:30"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":650}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/zone-kathmandu","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"Asia/Kathmandu"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"Asia/Kathmandu"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"Asia/Kathmandu"}]},"end":"2026-08-18T04:15:45+05:45","start":"2026-08-18T04:15:00+05:45"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":650}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/zone-st-johns","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"America/St_Johns"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/St_Johns"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/St_Johns"}]},"end":"2026-08-17T20:00:45-02:30","start":"2026-08-17T20:00:00-02:30"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":650}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/zone-utc","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"UTC"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"GMT"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"GMT"}]},"end":"2026-08-17T22:30:45Z","start":"2026-08-17T22:30:00Z"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":650}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/repeated-hour-first/none","input":{"convert":{"source":{"context":"plain","end":1793521860,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":1793521800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"end":"2026-11-01T08:31:00Z","start":"2026-11-01T08:30:00Z"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":650}}],"warnings":["mobile-omission.source-offset@Observation.effectivePeriod.start","mobile-omission.source-offset@Observation.effectivePeriod.end"]}]}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/repeated-hour-first/los-angeles","input":{"convert":{"source":{"context":"plain","end":1793521860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":1793521800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-11-01T01:31:00-07:00","start":"2026-11-01T01:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":650}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/repeated-hour-second/none","input":{"convert":{"source":{"context":"plain","end":1793525460,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":1793525400,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"end":"2026-11-01T09:31:00Z","start":"2026-11-01T09:30:00Z"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":650}}],"warnings":["mobile-omission.source-offset@Observation.effectivePeriod.start","mobile-omission.source-offset@Observation.effectivePeriod.end"]}]}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/repeated-hour-second/los-angeles","input":{"convert":{"source":{"context":"plain","end":1793525460,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":1793525400,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-11-01T01:31:00-08:00","start":"2026-11-01T01:30:00-08:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":650}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/lmt-1800/none","input":{"convert":{"source":{"context":"plain","end":-5364662340,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":-5364662400,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"end":"1800-01-01T00:01:00Z","start":"1800-01-01T00:00:00Z"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":650}}],"warnings":["mobile-omission.source-offset@Observation.effectivePeriod.start","mobile-omission.source-offset@Observation.effectivePeriod.end"]}]}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/lmt-1800/los-angeles","input":{"convert":{"source":{"context":"plain","end":-5364662340,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":-5364662400,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryEnergyConsumed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/fraction-250/none","input":{"convert":{"source":{"context":"plain","end":1787148660.25,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":1787148600.25,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"end":"2026-08-19T14:11:00.250Z","start":"2026-08-19T14:10:00.250Z"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":650}}],"warnings":["mobile-omission.source-offset@Observation.effectivePeriod.start","mobile-omission.source-offset@Observation.effectivePeriod.end"]}]}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/fraction-250/los-angeles","input":{"convert":{"source":{"context":"plain","end":1787148660.25,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":1787148600.25,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-19T07:11:00.250-07:00","start":"2026-08-19T07:10:00.250-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":650}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/tie-even/none","input":{"convert":{"source":{"context":"plain","end":1787148660.0625,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":1787148600.0625,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"end":"2026-08-19T14:11:00.062Z","start":"2026-08-19T14:10:00.062Z"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":650}}],"warnings":["mobile-omission.source-offset@Observation.effectivePeriod.start","mobile-omission.source-offset@Observation.effectivePeriod.end"]}]}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/tie-even/los-angeles","input":{"convert":{"source":{"context":"plain","end":1787148660.0625,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":1787148600.0625,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-19T07:11:00.062-07:00","start":"2026-08-19T07:10:00.062-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":650}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/tie-odd/none","input":{"convert":{"source":{"context":"plain","end":1787148660.1875,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":1787148600.1875,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"end":"2026-08-19T14:11:00.188Z","start":"2026-08-19T14:10:00.188Z"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":650}}],"warnings":["mobile-omission.source-offset@Observation.effectivePeriod.start","mobile-omission.source-offset@Observation.effectivePeriod.end"]}]}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/tie-odd/los-angeles","input":{"convert":{"source":{"context":"plain","end":1787148660.1875,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":1787148600.1875,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-19T07:11:00.188-07:00","start":"2026-08-19T07:10:00.188-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":650}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/year-9999/none","input":{"convert":{"source":{"context":"plain","end":253402300859,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":253402300799,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryEnergyConsumed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/year-9999/los-angeles","input":{"convert":{"source":{"context":"plain","end":253402300859,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":253402300799,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"9999-12-31T16:00:59-08:00","start":"9999-12-31T15:59:59-08:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":650}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/year-10000/none","input":{"convert":{"source":{"context":"plain","end":253402300860,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":253402300800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryEnergyConsumed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/year-10000/los-angeles","input":{"convert":{"source":{"context":"plain","end":253402300860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":253402300800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"9999-12-31T16:01:00-08:00","start":"9999-12-31T16:00:00-08:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":650}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/pre-reform-1500/none","input":{"convert":{"source":{"context":"plain","end":-14831769540,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":-14831769600,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"end":"1500-01-01T00:01:00Z","start":"1500-01-01T00:00:00Z"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":650}}],"warnings":["mobile-omission.source-offset@Observation.effectivePeriod.start","mobile-omission.source-offset@Observation.effectivePeriod.end"]}]}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/pre-reform-1500/los-angeles","input":{"convert":{"source":{"context":"plain","end":-14831769540,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":-14831769600,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryEnergyConsumed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/year-1/none","input":{"convert":{"source":{"context":"plain","end":-62135596740,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":-62135596800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"9052-2","display":"Calorie intake total","system":"http://loinc.org"}]},"effectivePeriod":{"end":"0001-01-01T00:01:00Z","start":"0001-01-01T00:00:00Z"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3eg08UkhWZg31TtofTiIiFo42HFr6kIuHx_ElwRfG_8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":650}}],"warnings":["mobile-omission.source-offset@Observation.effectivePeriod.start","mobile-omission.source-offset@Observation.effectivePeriod.end"]}]}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/year-1/los-angeles","input":{"convert":{"source":{"context":"plain","end":-62135596740,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":-62135596800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryEnergyConsumed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/year-0/none","input":{"convert":{"source":{"context":"plain","end":-62135596741,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":-62135596801,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryEnergyConsumed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierDietaryEnergyConsumed/year-0/los-angeles","input":{"convert":{"source":{"context":"plain","end":-62135596741,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":650}},"start":-62135596801,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.dietaryEnergyConsumed, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierStepCount/equal","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stepCount, GroveHealthKitFHIR.HealthKitValueFailure.effectivePeriodInvalid)","location":"HKSample.startDate"}}} +{"id":"time/HKQuantityTypeIdentifierStepCount/interval-45s","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:45-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":120}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierStepCount/reversed-45s","input":{"convert":{"source":{"context":"plain","end":1787005755,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stepCount, GroveHealthKitFHIR.HealthKitValueFailure.effectivePeriodInvalid)","location":"HKSample.startDate"}}} +{"id":"time/HKQuantityTypeIdentifierStepCount/zone-none","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"end":"2026-08-17T22:30:45Z","start":"2026-08-17T22:30:00Z"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":120}}],"warnings":["mobile-omission.source-offset@Observation.effectivePeriod.start","mobile-omission.source-offset@Observation.effectivePeriod.end"]}]}} +{"id":"time/HKQuantityTypeIdentifierStepCount/zone-invalid","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"Not/A-Time-Zone"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stepCount, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.timeZone))","location":"HKSample.metadata[HKTimeZone]"}}} +{"id":"time/HKQuantityTypeIdentifierStepCount/zone-wrong-type","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"integer":42}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stepCount, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.timeZone))","location":"HKSample.metadata[HKTimeZone]"}}} +{"id":"time/HKQuantityTypeIdentifierStepCount/zone-los-angeles","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:45-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":120}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierStepCount/zone-kolkata","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"Asia/Kolkata"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"Asia/Kolkata"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"Asia/Kolkata"}]},"end":"2026-08-18T04:00:45+05:30","start":"2026-08-18T04:00:00+05:30"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":120}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierStepCount/zone-kathmandu","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"Asia/Kathmandu"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"Asia/Kathmandu"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"Asia/Kathmandu"}]},"end":"2026-08-18T04:15:45+05:45","start":"2026-08-18T04:15:00+05:45"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":120}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierStepCount/zone-st-johns","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"America/St_Johns"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/St_Johns"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/St_Johns"}]},"end":"2026-08-17T20:00:45-02:30","start":"2026-08-17T20:00:00-02:30"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":120}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierStepCount/zone-utc","input":{"convert":{"source":{"context":"plain","end":1787005845,"metadata":{"HKTimeZone":{"string":"UTC"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"GMT"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"GMT"}]},"end":"2026-08-17T22:30:45Z","start":"2026-08-17T22:30:00Z"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":120}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierStepCount/repeated-hour-first/none","input":{"convert":{"source":{"context":"plain","end":1793521860,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":1793521800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"end":"2026-11-01T08:31:00Z","start":"2026-11-01T08:30:00Z"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":120}}],"warnings":["mobile-omission.source-offset@Observation.effectivePeriod.start","mobile-omission.source-offset@Observation.effectivePeriod.end"]}]}} +{"id":"time/HKQuantityTypeIdentifierStepCount/repeated-hour-first/los-angeles","input":{"convert":{"source":{"context":"plain","end":1793521860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":1793521800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-11-01T01:31:00-07:00","start":"2026-11-01T01:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":120}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierStepCount/repeated-hour-second/none","input":{"convert":{"source":{"context":"plain","end":1793525460,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":1793525400,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"end":"2026-11-01T09:31:00Z","start":"2026-11-01T09:30:00Z"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":120}}],"warnings":["mobile-omission.source-offset@Observation.effectivePeriod.start","mobile-omission.source-offset@Observation.effectivePeriod.end"]}]}} +{"id":"time/HKQuantityTypeIdentifierStepCount/repeated-hour-second/los-angeles","input":{"convert":{"source":{"context":"plain","end":1793525460,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":1793525400,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-11-01T01:31:00-08:00","start":"2026-11-01T01:30:00-08:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":120}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierStepCount/lmt-1800/none","input":{"convert":{"source":{"context":"plain","end":-5364662340,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":-5364662400,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"end":"1800-01-01T00:01:00Z","start":"1800-01-01T00:00:00Z"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":120}}],"warnings":["mobile-omission.source-offset@Observation.effectivePeriod.start","mobile-omission.source-offset@Observation.effectivePeriod.end"]}]}} +{"id":"time/HKQuantityTypeIdentifierStepCount/lmt-1800/los-angeles","input":{"convert":{"source":{"context":"plain","end":-5364662340,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":-5364662400,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stepCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierStepCount/fraction-250/none","input":{"convert":{"source":{"context":"plain","end":1787148660.25,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":1787148600.25,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"end":"2026-08-19T14:11:00.250Z","start":"2026-08-19T14:10:00.250Z"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":120}}],"warnings":["mobile-omission.source-offset@Observation.effectivePeriod.start","mobile-omission.source-offset@Observation.effectivePeriod.end"]}]}} +{"id":"time/HKQuantityTypeIdentifierStepCount/fraction-250/los-angeles","input":{"convert":{"source":{"context":"plain","end":1787148660.25,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":1787148600.25,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-19T07:11:00.250-07:00","start":"2026-08-19T07:10:00.250-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":120}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierStepCount/tie-even/none","input":{"convert":{"source":{"context":"plain","end":1787148660.0625,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":1787148600.0625,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"end":"2026-08-19T14:11:00.062Z","start":"2026-08-19T14:10:00.062Z"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":120}}],"warnings":["mobile-omission.source-offset@Observation.effectivePeriod.start","mobile-omission.source-offset@Observation.effectivePeriod.end"]}]}} +{"id":"time/HKQuantityTypeIdentifierStepCount/tie-even/los-angeles","input":{"convert":{"source":{"context":"plain","end":1787148660.0625,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":1787148600.0625,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-19T07:11:00.062-07:00","start":"2026-08-19T07:10:00.062-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":120}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierStepCount/tie-odd/none","input":{"convert":{"source":{"context":"plain","end":1787148660.1875,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":1787148600.1875,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"end":"2026-08-19T14:11:00.188Z","start":"2026-08-19T14:10:00.188Z"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":120}}],"warnings":["mobile-omission.source-offset@Observation.effectivePeriod.start","mobile-omission.source-offset@Observation.effectivePeriod.end"]}]}} +{"id":"time/HKQuantityTypeIdentifierStepCount/tie-odd/los-angeles","input":{"convert":{"source":{"context":"plain","end":1787148660.1875,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":1787148600.1875,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-19T07:11:00.188-07:00","start":"2026-08-19T07:10:00.188-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":120}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierStepCount/year-9999/none","input":{"convert":{"source":{"context":"plain","end":253402300859,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":253402300799,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stepCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierStepCount/year-9999/los-angeles","input":{"convert":{"source":{"context":"plain","end":253402300859,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":253402300799,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"9999-12-31T16:00:59-08:00","start":"9999-12-31T15:59:59-08:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":120}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierStepCount/year-10000/none","input":{"convert":{"source":{"context":"plain","end":253402300860,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":253402300800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stepCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierStepCount/year-10000/los-angeles","input":{"convert":{"source":{"context":"plain","end":253402300860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":253402300800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"9999-12-31T16:01:00-08:00","start":"9999-12-31T16:00:00-08:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":120}}],"warnings":[]}]}} +{"id":"time/HKQuantityTypeIdentifierStepCount/pre-reform-1500/none","input":{"convert":{"source":{"context":"plain","end":-14831769540,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":-14831769600,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"end":"1500-01-01T00:01:00Z","start":"1500-01-01T00:00:00Z"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":120}}],"warnings":["mobile-omission.source-offset@Observation.effectivePeriod.start","mobile-omission.source-offset@Observation.effectivePeriod.end"]}]}} +{"id":"time/HKQuantityTypeIdentifierStepCount/pre-reform-1500/los-angeles","input":{"convert":{"source":{"context":"plain","end":-14831769540,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":-14831769600,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stepCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierStepCount/year-1/none","input":{"convert":{"source":{"context":"plain","end":-62135596740,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":-62135596800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"end":"0001-01-01T00:01:00Z","start":"0001-01-01T00:00:00Z"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":120}}],"warnings":["mobile-omission.source-offset@Observation.effectivePeriod.start","mobile-omission.source-offset@Observation.effectivePeriod.end"]}]}} +{"id":"time/HKQuantityTypeIdentifierStepCount/year-1/los-angeles","input":{"convert":{"source":{"context":"plain","end":-62135596740,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":-62135596800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stepCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierStepCount/year-0/none","input":{"convert":{"source":{"context":"plain","end":-62135596741,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":-62135596801,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stepCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"time/HKQuantityTypeIdentifierStepCount/year-0/los-angeles","input":{"convert":{"source":{"context":"plain","end":-62135596741,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":-62135596801,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stepCount, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"correlation/blood-pressure/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"correlation":{"members":[{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":120},{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":80}],"type":"HKCorrelationTypeIdentifierBloodPressure"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"85354-9","display":"Blood pressure panel with all children optional","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"8480-6","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":120}},{"code":{"coding":[{"code":"8462-4","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":80}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCorrelationTypeIdentifierBloodPressure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:doVPnvrBLloit0idVcBN7j360amKQX_nsASUbcTd7a8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wYZqj9o2nHYQ_5L_6eXr6AyxGkXTo2hPBmQu8SUzugY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-pressure","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}}],"warnings":[]}]}} +{"id":"correlation/blood-pressure/interval","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"correlation":{"members":[{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":120},{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":80}],"type":"HKCorrelationTypeIdentifierBloodPressure"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"85354-9","display":"Blood pressure panel with all children optional","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"8480-6","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":120}},{"code":{"coding":[{"code":"8462-4","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":80}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCorrelationTypeIdentifierBloodPressure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:doVPnvrBLloit0idVcBN7j360amKQX_nsASUbcTd7a8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wYZqj9o2nHYQ_5L_6eXr6AyxGkXTo2hPBmQu8SUzugY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-pressure","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}}],"warnings":[]}]}} +{"id":"correlation/blood-pressure/missing-systolic","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"correlation":{"members":[{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":80}],"type":"HKCorrelationTypeIdentifierBloodPressure"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.required-component-missing","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bloodPressure, GroveHealthKitFHIR.HealthKitValueFailure.requiredComponentMissing(component: \"systolic\"))","location":"HKCorrelation.objects[systolic]"}}} +{"id":"correlation/blood-pressure/missing-diastolic","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"correlation":{"members":[{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":120}],"type":"HKCorrelationTypeIdentifierBloodPressure"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.required-component-missing","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bloodPressure, GroveHealthKitFHIR.HealthKitValueFailure.requiredComponentMissing(component: \"diastolic\"))","location":"HKCorrelation.objects[diastolic]"}}} +{"id":"correlation/blood-pressure/no-members","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"correlation":{"members":[],"type":"HKCorrelationTypeIdentifierBloodPressure"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.required-component-missing","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bloodPressure, GroveHealthKitFHIR.HealthKitValueFailure.requiredComponentMissing(component: \"systolic\"))","location":"HKCorrelation.objects[systolic]"}}} +{"id":"correlation/blood-pressure/extra-heart-rate","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"correlation":{"members":[{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":120},{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":80},{"metadata":{},"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":60}],"type":"HKCorrelationTypeIdentifierBloodPressure"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"85354-9","display":"Blood pressure panel with all children optional","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"8480-6","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":120}},{"code":{"coding":[{"code":"8462-4","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":80}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCorrelationTypeIdentifierBloodPressure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:doVPnvrBLloit0idVcBN7j360amKQX_nsASUbcTd7a8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wYZqj9o2nHYQ_5L_6eXr6AyxGkXTo2hPBmQu8SUzugY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-pressure","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}}],"warnings":[]}]}} +{"id":"correlation/blood-pressure/systolic-nan","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"correlation":{"members":[{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":"NaN"},{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":80}],"type":"HKCorrelationTypeIdentifierBloodPressure"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bloodPressure, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"correlation/blood-pressure/systolic-negative","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"correlation":{"members":[{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":-1},{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":80}],"type":"HKCorrelationTypeIdentifierBloodPressure"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"85354-9","display":"Blood pressure panel with all children optional","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"8480-6","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":-1}},{"code":{"coding":[{"code":"8462-4","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":80}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCorrelationTypeIdentifierBloodPressure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:doVPnvrBLloit0idVcBN7j360amKQX_nsASUbcTd7a8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wYZqj9o2nHYQ_5L_6eXr6AyxGkXTo2hPBmQu8SUzugY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-pressure","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}}],"warnings":[]}]}} +{"id":"correlation/blood-pressure/systolic-huge","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"correlation":{"members":[{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":1e+21},{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":80}],"type":"HKCorrelationTypeIdentifierBloodPressure"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"85354-9","display":"Blood pressure panel with all children optional","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"8480-6","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":1000000000000000000000}},{"code":{"coding":[{"code":"8462-4","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":80}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCorrelationTypeIdentifierBloodPressure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:doVPnvrBLloit0idVcBN7j360amKQX_nsASUbcTd7a8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wYZqj9o2nHYQ_5L_6eXr6AyxGkXTo2hPBmQu8SUzugY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-pressure","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}}],"warnings":[]}]}} +{"id":"correlation/blood-pressure/systolic-fractional","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"correlation":{"members":[{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":120.5},{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":80}],"type":"HKCorrelationTypeIdentifierBloodPressure"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"85354-9","display":"Blood pressure panel with all children optional","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"8480-6","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":120.5}},{"code":{"coding":[{"code":"8462-4","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":80}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCorrelationTypeIdentifierBloodPressure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:doVPnvrBLloit0idVcBN7j360amKQX_nsASUbcTd7a8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wYZqj9o2nHYQ_5L_6eXr6AyxGkXTo2hPBmQu8SUzugY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-pressure","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}}],"warnings":[]}]}} +{"id":"correlation/blood-pressure/diastolic-zero","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"correlation":{"members":[{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":120},{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":0}],"type":"HKCorrelationTypeIdentifierBloodPressure"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"85354-9","display":"Blood pressure panel with all children optional","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"8480-6","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":120}},{"code":{"coding":[{"code":"8462-4","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":0}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCorrelationTypeIdentifierBloodPressure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:doVPnvrBLloit0idVcBN7j360amKQX_nsASUbcTd7a8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wYZqj9o2nHYQ_5L_6eXr6AyxGkXTo2hPBmQu8SUzugY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-pressure","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}}],"warnings":[]}]}} +{"id":"correlation/blood-pressure/member-zone-differs","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"correlation":{"members":[{"metadata":{"HKTimeZone":{"string":"Asia/Kolkata"}},"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":120},{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":80}],"type":"HKCorrelationTypeIdentifierBloodPressure"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"85354-9","display":"Blood pressure panel with all children optional","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"8480-6","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":120}},{"code":{"coding":[{"code":"8462-4","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":80}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCorrelationTypeIdentifierBloodPressure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:doVPnvrBLloit0idVcBN7j360amKQX_nsASUbcTd7a8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wYZqj9o2nHYQ_5L_6eXr6AyxGkXTo2hPBmQu8SUzugY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-pressure","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}}],"warnings":[]}]}} +{"id":"correlation/blood-pressure/member-zones-agree-correlation-none","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{},"record":{"correlation":{"members":[{"metadata":{"HKTimeZone":{"string":"Asia/Kolkata"}},"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":120},{"metadata":{"HKTimeZone":{"string":"Asia/Kolkata"}},"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":80}],"type":"HKCorrelationTypeIdentifierBloodPressure"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"85354-9","display":"Blood pressure panel with all children optional","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"8480-6","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":120}},{"code":{"coding":[{"code":"8462-4","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":80}}],"effectiveDateTime":"2026-08-17T22:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCorrelationTypeIdentifierBloodPressure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:doVPnvrBLloit0idVcBN7j360amKQX_nsASUbcTd7a8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wYZqj9o2nHYQ_5L_6eXr6AyxGkXTo2hPBmQu8SUzugY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-pressure","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}}],"warnings":["mobile-omission.source-offset@Observation.effectiveDateTime"]}]}} +{"id":"correlation/blood-pressure/member-zones-disagree-correlation-none","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{},"record":{"correlation":{"members":[{"metadata":{"HKTimeZone":{"string":"Asia/Kolkata"}},"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":120},{"metadata":{"HKTimeZone":{"string":"Asia/Kathmandu"}},"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":80}],"type":"HKCorrelationTypeIdentifierBloodPressure"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"85354-9","display":"Blood pressure panel with all children optional","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"8480-6","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":120}},{"code":{"coding":[{"code":"8462-4","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":80}}],"effectiveDateTime":"2026-08-17T22:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCorrelationTypeIdentifierBloodPressure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:doVPnvrBLloit0idVcBN7j360amKQX_nsASUbcTd7a8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wYZqj9o2nHYQ_5L_6eXr6AyxGkXTo2hPBmQu8SUzugY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-pressure","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}}],"warnings":["mobile-omission.source-offset@Observation.effectiveDateTime"]}]}} +{"id":"correlation/blood-pressure/member-zone-invalid-correlation-none","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{},"record":{"correlation":{"members":[{"metadata":{"HKTimeZone":{"string":"Not/A-Time-Zone"}},"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":120},{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":80}],"type":"HKCorrelationTypeIdentifierBloodPressure"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"85354-9","display":"Blood pressure panel with all children optional","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"8480-6","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":120}},{"code":{"coding":[{"code":"8462-4","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":80}}],"effectiveDateTime":"2026-08-17T22:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCorrelationTypeIdentifierBloodPressure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:doVPnvrBLloit0idVcBN7j360amKQX_nsASUbcTd7a8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wYZqj9o2nHYQ_5L_6eXr6AyxGkXTo2hPBmQu8SUzugY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-pressure","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}}],"warnings":["mobile-omission.source-offset@Observation.effectiveDateTime"]}]}} +{"id":"correlation/blood-pressure/member-user-entered","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"correlation":{"members":[{"metadata":{"HKWasUserEntered":{"boolean":true}},"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":120},{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":80}],"type":"HKCorrelationTypeIdentifierBloodPressure"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"85354-9","display":"Blood pressure panel with all children optional","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"8480-6","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":120}},{"code":{"coding":[{"code":"8462-4","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":80}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCorrelationTypeIdentifierBloodPressure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:doVPnvrBLloit0idVcBN7j360amKQX_nsASUbcTd7a8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wYZqj9o2nHYQ_5L_6eXr6AyxGkXTo2hPBmQu8SUzugY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-pressure","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}}],"warnings":[]}]}} +{"id":"correlation/blood-pressure/member-user-entered-correlation-not","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"},"HKWasUserEntered":{"boolean":false}},"record":{"correlation":{"members":[{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":120},{"metadata":{"HKWasUserEntered":{"boolean":true}},"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":80}],"type":"HKCorrelationTypeIdentifierBloodPressure"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"85354-9","display":"Blood pressure panel with all children optional","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"8480-6","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":120}},{"code":{"coding":[{"code":"8462-4","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":80}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCorrelationTypeIdentifierBloodPressure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:doVPnvrBLloit0idVcBN7j360amKQX_nsASUbcTd7a8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wYZqj9o2nHYQ_5L_6eXr6AyxGkXTo2hPBmQu8SUzugY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-pressure","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}}],"warnings":[]}]}} +{"id":"correlation/blood-pressure/member-foreign-key","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"correlation":{"members":[{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":120},{"metadata":{"org.example.member":{"string":"x"}},"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":80}],"type":"HKCorrelationTypeIdentifierBloodPressure"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"85354-9","display":"Blood pressure panel with all children optional","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"8480-6","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":120}},{"code":{"coding":[{"code":"8462-4","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":80}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCorrelationTypeIdentifierBloodPressure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:doVPnvrBLloit0idVcBN7j360amKQX_nsASUbcTd7a8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wYZqj9o2nHYQ_5L_6eXr6AyxGkXTo2hPBmQu8SUzugY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-pressure","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}}],"warnings":[]}]}} +{"id":"correlation/blood-pressure/member-sync-identity","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"correlation":{"members":[{"metadata":{"HKMetadataKeySyncIdentifier":{"string":"member-sync"},"HKMetadataKeySyncVersion":{"integer":1}},"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":120},{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":80}],"type":"HKCorrelationTypeIdentifierBloodPressure"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"85354-9","display":"Blood pressure panel with all children optional","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"8480-6","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":120}},{"code":{"coding":[{"code":"8462-4","system":"http://loinc.org"}]},"valueQuantity":{"code":"mm[Hg]","system":"http://unitsofmeasure.org","unit":"mmHg","value":80}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCorrelationTypeIdentifierBloodPressure"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:doVPnvrBLloit0idVcBN7j360amKQX_nsASUbcTd7a8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wYZqj9o2nHYQ_5L_6eXr6AyxGkXTo2hPBmQu8SUzugY"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-pressure","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}}],"warnings":[]}]}} +{"id":"correlation/food/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"correlation":{"members":[{"metadata":{},"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed","unit":"kcal","value":320}],"type":"HKCorrelationTypeIdentifierFood"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"unsupportedSourceType(GroveHealthKitFHIR.HealthKitSourceType.food)","location":"HKSample.sampleType"}}} +{"id":"workout/activity/0","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":0,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/1","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":1,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"american-football","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"americanFootball","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/2","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":2,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"archery","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/3","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":3,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"australianFootball","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/4","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":4,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"badminton","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"badminton","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/5","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":5,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"baseball","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"baseball","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/6","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":6,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"basketball","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"basketball","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/7","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":7,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"bowling","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/8","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":8,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"boxing","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"boxing","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/9","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":9,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"climbing","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/10","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":10,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"cricket","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/11","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":11,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"crossTraining","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/12","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":12,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"curling","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/13","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":13,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1002}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"cycling","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"cycling","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/14","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":14,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"dancing","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"dance","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/15","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":15,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"dancing","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"danceInspiredTraining","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/16","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":16,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"elliptical","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"elliptical","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/17","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":17,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"equestrianSports","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/18","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":18,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"fencing","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/19","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":19,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"fishing","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/20","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":20,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"strength-training","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"functionalStrengthTraining","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/21","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":21,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"golf","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"golf","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/22","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":22,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"gymnastics","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/23","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":23,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"handball","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/24","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":24,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"hiking","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"hiking","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/25","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":25,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"hockey","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/26","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":26,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"hunting","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/27","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":27,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"lacrosse","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/28","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":28,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"martial-arts","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"martialArts","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/29","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":29,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"mindAndBody","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/30","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":30,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"mixedMetabolicCardioTraining","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/31","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":31,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1008}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"paddleSports","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/32","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":32,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"play","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/33","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":33,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"preparationAndRecovery","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/34","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":34,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"racquetball","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/35","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":35,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1006}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"rowing","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"rowing","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/36","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":36,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"rugby","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/37","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":37,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"running","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"running","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/38","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":38,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1008}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"sailing","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/39","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":39,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1009}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"skatingSports","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/40","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":40,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1007}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"snowSports","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/41","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":41,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"soccer","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"soccer","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/42","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":42,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"baseball","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"softball","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/43","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":43,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"squash","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"squash","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/44","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":44,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"stair-climbing","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"stairClimbing","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/45","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":45,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1008}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"surfingSports","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/46","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":46,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1003}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"swimming","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"swimming","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/47","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":47,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"table-tennis","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"tableTennis","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/48","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":48,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"tennis","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"tennis","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/49","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":49,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"trackAndField","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/50","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":50,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"strength-training","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"traditionalStrengthTraining","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/51","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":51,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"volleyball","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"volleyball","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/52","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":52,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"walking","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"walking","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/53","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":53,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"swimming","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"waterFitness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/54","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":54,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"waterPolo","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/55","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":55,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"swimming","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"waterSports","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/56","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":56,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"martial-arts","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"wrestling","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/57","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":57,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"yoga","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"yoga","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/58","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":58,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"dancing","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"barre","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/59","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":59,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"strength-training","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"coreTraining","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/60","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":60,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1005}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"skiing","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"crossCountrySkiing","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/61","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":61,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1007}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"skiing","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"downhillSkiing","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/62","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":62,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"flexibility","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/63","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":63,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"high-intensity-interval-training","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"highIntensityIntervalTraining","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/64","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":64,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"jumpRope","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/65","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":65,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"boxing","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"kickboxing","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/66","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":66,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"pilates","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"pilates","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/67","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":67,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1007}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"snowboarding","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"snowboarding","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/68","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":68,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"stair-climbing","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"stairs","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/69","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":69,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"stair-climbing","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"stepTraining","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/70","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":70,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1004}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"walking","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"wheelchairWalkPace","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/71","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":71,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1004}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"running","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"wheelchairRunPace","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/72","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":72,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"martial-arts","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"taiChi","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/73","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":73,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"mixedCardio","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/74","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":74,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1002}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"cycling","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"handCycling","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/75","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":75,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"discSports","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/76","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":76,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"fitnessGaming","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/77","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":77,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"dancing","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"cardioDance","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/78","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":78,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"dancing","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"socialDance","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/79","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":79,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"pickleball","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/80","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":80,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"cooldown","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/81","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":81,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/82","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":82,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"swimBikeRun","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/83","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":83,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"transition","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/84","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":84,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"underwaterDiving","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/85","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":85,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/86","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":86,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/87","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":87,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/88","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":88,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/89","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":89,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/90","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":90,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/3000","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":3000,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"other","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/activity/9999","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":9999,"duration":3600,"statistics":[{"sum":1001,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"},{"sum":1002,"type":"HKQuantityTypeIdentifierDistanceCycling","unit":"m"},{"sum":1003,"type":"HKQuantityTypeIdentifierDistanceSwimming","unit":"m"},{"sum":1004,"type":"HKQuantityTypeIdentifierDistanceWheelchair","unit":"m"},{"sum":1005,"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing","unit":"m"},{"sum":1006,"type":"HKQuantityTypeIdentifierDistanceRowing","unit":"m"},{"sum":1007,"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports","unit":"m"},{"sum":1008,"type":"HKQuantityTypeIdentifierDistancePaddleSports","unit":"m"},{"sum":1009,"type":"HKQuantityTypeIdentifierDistanceSkatingSports","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":1001}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"other","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/statistics/none","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":37,"duration":3600,"statistics":[]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"running","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"running","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/statistics/distance","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":37,"duration":3600,"statistics":[{"sum":10000,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":10000}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"running","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"running","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/statistics/energy","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":37,"duration":3600,"statistics":[{"sum":640,"type":"HKQuantityTypeIdentifierActiveEnergyBurned","unit":"kcal"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"active-energy-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":640}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"running","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"running","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/statistics/steps","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":37,"duration":3600,"statistics":[{"sum":9000,"type":"HKQuantityTypeIdentifierStepCount","unit":"count"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"step-count-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"{steps}","value":9000}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"running","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"running","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/statistics/flights","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":37,"duration":3600,"statistics":[{"sum":12,"type":"HKQuantityTypeIdentifierFlightsClimbed","unit":"count"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"flights-climbed-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"{flights}","system":"http://unitsofmeasure.org","unit":"{flights}","value":12}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"running","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"running","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/statistics/strokes","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":37,"duration":3600,"statistics":[{"sum":900,"type":"HKQuantityTypeIdentifierSwimmingStrokeCount","unit":"count"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"swimming-stroke-count-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"{strokes}","system":"http://unitsofmeasure.org","unit":"{strokes}","value":900}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"running","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"running","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/statistics/heart-rate","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":37,"duration":3600,"statistics":[{"average":140,"maximum":171,"minimum":95,"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"heart-rate-avg","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"/min","value":140}},{"code":{"coding":[{"code":"heart-rate-max","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"/min","value":171}},{"code":{"coding":[{"code":"heart-rate-min","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"/min","value":95}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"running","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"running","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/statistics/all","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":37,"duration":3600,"statistics":[{"average":140,"maximum":171,"minimum":95,"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min"},{"sum":900,"type":"HKQuantityTypeIdentifierSwimmingStrokeCount","unit":"count"},{"sum":12,"type":"HKQuantityTypeIdentifierFlightsClimbed","unit":"count"},{"sum":9000,"type":"HKQuantityTypeIdentifierStepCount","unit":"count"},{"sum":640,"type":"HKQuantityTypeIdentifierActiveEnergyBurned","unit":"kcal"},{"sum":10000,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":10000}},{"code":{"coding":[{"code":"active-energy-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":640}},{"code":{"coding":[{"code":"step-count-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"{steps}","value":9000}},{"code":{"coding":[{"code":"flights-climbed-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"{flights}","system":"http://unitsofmeasure.org","unit":"{flights}","value":12}},{"code":{"coding":[{"code":"swimming-stroke-count-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"{strokes}","system":"http://unitsofmeasure.org","unit":"{strokes}","value":900}},{"code":{"coding":[{"code":"heart-rate-avg","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"/min","value":140}},{"code":{"coding":[{"code":"heart-rate-max","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"/min","value":171}},{"code":{"coding":[{"code":"heart-rate-min","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"/min","value":95}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"running","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"running","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/statistics/heart-rate-average-only","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":37,"duration":3600,"statistics":[{"average":140,"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"heart-rate-avg","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"/min","value":140}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"running","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"running","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/statistics/heart-rate-extremes-only","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":37,"duration":3600,"statistics":[{"maximum":171,"minimum":95,"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"heart-rate-max","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"/min","value":171}},{"code":{"coding":[{"code":"heart-rate-min","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"/min","value":95}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"running","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"running","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/statistics/heart-rate-without-readings","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":37,"duration":3600,"statistics":[{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"running","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"running","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/statistics/heart-rate-nan-average","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":37,"duration":3600,"statistics":[{"average":"NaN","maximum":171,"minimum":95,"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.workout, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"workout/statistics/energy-nan","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":37,"duration":3600,"statistics":[{"sum":"NaN","type":"HKQuantityTypeIdentifierActiveEnergyBurned","unit":"kcal"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.workout, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"workout/statistics/energy-zero","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":37,"duration":3600,"statistics":[{"sum":0,"type":"HKQuantityTypeIdentifierActiveEnergyBurned","unit":"kcal"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"active-energy-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"kcal","system":"http://unitsofmeasure.org","unit":"kcal","value":0}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"running","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"running","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/statistics/distance-negative","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":37,"duration":3600,"statistics":[{"sum":-1,"type":"HKQuantityTypeIdentifierDistanceWalkingRunning","unit":"m"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"distance-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"m","system":"http://unitsofmeasure.org","unit":"m","value":-1}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"running","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"running","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/statistics/steps-fractional","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":37,"duration":3600,"statistics":[{"sum":1.5,"type":"HKQuantityTypeIdentifierStepCount","unit":"count"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}},{"code":{"coding":[{"code":"step-count-sum","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"{steps}","value":1.5}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"running","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"running","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/statistics/energy-average-only","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":37,"duration":3600,"statistics":[{"average":320,"type":"HKQuantityTypeIdentifierActiveEnergyBurned","unit":"kcal"}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"running","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"running","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/duration/zero","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":37,"duration":0,"statistics":[]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":0}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"running","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"running","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/duration/fractional","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":37,"duration":1.5,"statistics":[]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":1.5}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"running","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"running","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/duration/negative","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":37,"duration":-1,"statistics":[]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":-1}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"running","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"running","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"workout/duration/nan","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":37,"duration":"NaN","statistics":[]}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.workout, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"workout/reversed","input":{"convert":{"source":{"context":"plain","end":1787005740,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workout":{"activity":37,"duration":3600,"statistics":[]}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.workout, GroveHealthKitFHIR.HealthKitValueFailure.effectivePeriodInvalid)","location":"HKSample.startDate"}}} +{"id":"workout/user-entered","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"},"HKWasUserEntered":{"boolean":true}},"record":{"workout":{"activity":37,"duration":3600,"statistics":[]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"workout","display":"Workout session","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"active-duration","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-statistic"}]},"valueQuantity":{"code":"s","system":"http://unitsofmeasure.org","unit":"s","value":3600}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T16:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutTypeIdentifier"},{"url":"https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-method","valueCoding":{"code":"manual-entry","display":"Manual entry","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-recording-method"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PgclD9Ko6YVqO5Gs6qLfhc-bAX-Wmt6osKaXaqsCa44"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"running","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-workout-activity"},{"code":"running","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-workout-activity"}]}}],"warnings":[]}]}} +{"id":"state-of-mind/row","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17],"kind":1,"labels":[17],"valence":0.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"pleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":0.5}}],"warnings":[]}]}} +{"id":"state-of-mind/interval","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17],"kind":1,"labels":[17],"valence":0.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"pleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":0.5}}],"warnings":[]}]}} +{"id":"state-of-mind/kind/2","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17],"kind":2,"labels":[17],"valence":0.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"daily-mood","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"pleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":0.5}}],"warnings":[]}]}} +{"id":"state-of-mind/kind/0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17],"kind":0,"labels":[17],"valence":0.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"pleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":0.5}}],"warnings":[]}]}} +{"id":"state-of-mind/kind/99","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17],"kind":99,"labels":[17],"valence":0.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"pleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":0.5}}],"warnings":[]}]}} +{"id":"state-of-mind/valence/-1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17],"kind":1,"labels":[17],"valence":-1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"very-unpleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":-1}}],"warnings":[]}]}} +{"id":"state-of-mind/valence/-0.9","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17],"kind":1,"labels":[17],"valence":-0.9}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"very-unpleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":-0.9}}],"warnings":[]}]}} +{"id":"state-of-mind/valence/-0.6","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17],"kind":1,"labels":[17],"valence":-0.6}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"unpleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":-0.6}}],"warnings":[]}]}} +{"id":"state-of-mind/valence/-0.3","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17],"kind":1,"labels":[17],"valence":-0.3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"slightly-unpleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":-0.3}}],"warnings":[]}]}} +{"id":"state-of-mind/valence/-0.1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17],"kind":1,"labels":[17],"valence":-0.1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"neutral","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":-0.1}}],"warnings":[]}]}} +{"id":"state-of-mind/valence/0.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17],"kind":1,"labels":[17],"valence":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"neutral","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":0}}],"warnings":[]}]}} +{"id":"state-of-mind/valence/0.1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17],"kind":1,"labels":[17],"valence":0.1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"neutral","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":0.1}}],"warnings":[]}]}} +{"id":"state-of-mind/valence/0.3","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17],"kind":1,"labels":[17],"valence":0.3}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"slightly-pleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":0.3}}],"warnings":[]}]}} +{"id":"state-of-mind/valence/0.6","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17],"kind":1,"labels":[17],"valence":0.6}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"pleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":0.6}}],"warnings":[]}]}} +{"id":"state-of-mind/valence/0.9","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17],"kind":1,"labels":[17],"valence":0.9}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"very-pleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":0.9}}],"warnings":[]}]}} +{"id":"state-of-mind/valence/1.0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17],"kind":1,"labels":[17],"valence":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"very-pleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":1}}],"warnings":[]}]}} +{"id":"state-of-mind/valence/0.30000000000000004","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17],"kind":1,"labels":[17],"valence":0.30000000000000004}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"slightly-pleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":0.30000000000000004}}],"warnings":[]}]}} +{"id":"state-of-mind/labels/none","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17],"kind":1,"labels":[],"valence":0.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"pleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":0.5}}],"warnings":[]}]}} +{"id":"state-of-mind/labels/every-raw","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17],"kind":1,"labels":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41],"valence":0.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"pleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"amazed","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"amused","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"angry","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"annoyed","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"anxious","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"ashamed","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"brave","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"calm","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"confident","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"content","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"disappointed","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"discouraged","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"disgusted","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"drained","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"embarrassed","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"excited","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"frustrated","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"grateful","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"guilty","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"hopeful","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"hopeless","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"indifferent","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"irritated","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"jealous","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"joyful","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"lonely","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"overwhelmed","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"passionate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"peaceful","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"proud","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"relieved","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"sad","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"satisfied","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"scared","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"stressed","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"surprised","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"worried","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":0.5}}],"warnings":[]}]}} +{"id":"state-of-mind/labels/unsorted","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17],"kind":1,"labels":[27,3,17,7],"valence":0.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"pleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"angry","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"calm","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"sad","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":0.5}}],"warnings":[]}]}} +{"id":"state-of-mind/labels/duplicate","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17],"kind":1,"labels":[17,17,3],"valence":0.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"pleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"angry","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":0.5}}],"warnings":[]}]}} +{"id":"state-of-mind/labels/unknown","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17],"kind":1,"labels":[999,17],"valence":0.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"pleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":0.5}}],"warnings":[]}]}} +{"id":"state-of-mind/associations/none","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[],"kind":1,"labels":[17],"valence":0.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"pleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":0.5}}],"warnings":[]}]}} +{"id":"state-of-mind/associations/every-raw","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21],"kind":1,"labels":[17],"valence":0.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"pleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"community","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"current-events","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"dating","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"education","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"family","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"fitness","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"friends","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"health","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"hobbies","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"identity","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"money","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"partner","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"self-care","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"spirituality","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"tasks","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"travel","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"weather","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":0.5}}],"warnings":[]}]}} +{"id":"state-of-mind/associations/unsorted","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17,5,8,1],"kind":1,"labels":[17],"valence":0.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"pleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"community","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"family","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"health","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":0.5}}],"warnings":[]}]}} +{"id":"state-of-mind/associations/duplicate","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[17,17,5],"kind":1,"labels":[17],"valence":0.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"pleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"family","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":0.5}}],"warnings":[]}]}} +{"id":"state-of-mind/associations/unknown","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"stateOfMind":{"associations":[999,17],"kind":1,"labels":[17],"valence":0.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"state-of-mind","display":"State of mind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"kind","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"momentary-emotion","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-kind"}]}},{"code":{"coding":[{"code":"valence-classification","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"pleasant","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-valence-classification"}]}},{"code":{"coding":[{"code":"state-of-mind-label","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"happy","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-label"}]}},{"code":{"coding":[{"code":"state-of-mind-association","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"work","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-state-of-mind-association"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeStateOfMind"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:0U0d2dJDVBb4EF6BnvvO-EQZOfbxAqo27Ij8qO8q0nQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"1","system":"http://unitsofmeasure.org","unit":"valence","value":0.5}}],"warnings":[]}]}} +{"id":"assessment/HKScoredAssessmentTypeIdentifierGAD7/-1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"assessment":{"score":-1,"type":"HKScoredAssessmentTypeIdentifierGAD7"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"70274-6","display":"Generalized anxiety disorder 7 item (GAD-7) total score [Reported.PHQ]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKScoredAssessmentTypeIdentifierGAD7"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:P7M62J1sdTk9est_QdxpEzZJA40w5NCaa4Fb_7wPVKE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jJ6ycLKU6-PsPqYTwQIf311qoeIidHNT4aQKTOZvQiI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-gad7-assessment"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{score}","system":"http://unitsofmeasure.org","unit":"score","value":-1}}],"warnings":[]}]}} +{"id":"assessment/HKScoredAssessmentTypeIdentifierGAD7/0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"assessment":{"score":0,"type":"HKScoredAssessmentTypeIdentifierGAD7"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"70274-6","display":"Generalized anxiety disorder 7 item (GAD-7) total score [Reported.PHQ]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKScoredAssessmentTypeIdentifierGAD7"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:P7M62J1sdTk9est_QdxpEzZJA40w5NCaa4Fb_7wPVKE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jJ6ycLKU6-PsPqYTwQIf311qoeIidHNT4aQKTOZvQiI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-gad7-assessment"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{score}","system":"http://unitsofmeasure.org","unit":"score","value":0}}],"warnings":[]}]}} +{"id":"assessment/HKScoredAssessmentTypeIdentifierGAD7/6","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"assessment":{"score":6,"type":"HKScoredAssessmentTypeIdentifierGAD7"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"70274-6","display":"Generalized anxiety disorder 7 item (GAD-7) total score [Reported.PHQ]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKScoredAssessmentTypeIdentifierGAD7"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:P7M62J1sdTk9est_QdxpEzZJA40w5NCaa4Fb_7wPVKE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jJ6ycLKU6-PsPqYTwQIf311qoeIidHNT4aQKTOZvQiI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-gad7-assessment"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{score}","system":"http://unitsofmeasure.org","unit":"score","value":6}}],"warnings":[]}]}} +{"id":"assessment/HKScoredAssessmentTypeIdentifierGAD7/21","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"assessment":{"score":21,"type":"HKScoredAssessmentTypeIdentifierGAD7"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"70274-6","display":"Generalized anxiety disorder 7 item (GAD-7) total score [Reported.PHQ]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKScoredAssessmentTypeIdentifierGAD7"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:P7M62J1sdTk9est_QdxpEzZJA40w5NCaa4Fb_7wPVKE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jJ6ycLKU6-PsPqYTwQIf311qoeIidHNT4aQKTOZvQiI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-gad7-assessment"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{score}","system":"http://unitsofmeasure.org","unit":"score","value":21}}],"warnings":[]}]}} +{"id":"assessment/HKScoredAssessmentTypeIdentifierGAD7/22","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"assessment":{"score":22,"type":"HKScoredAssessmentTypeIdentifierGAD7"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"70274-6","display":"Generalized anxiety disorder 7 item (GAD-7) total score [Reported.PHQ]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKScoredAssessmentTypeIdentifierGAD7"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:P7M62J1sdTk9est_QdxpEzZJA40w5NCaa4Fb_7wPVKE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jJ6ycLKU6-PsPqYTwQIf311qoeIidHNT4aQKTOZvQiI"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-gad7-assessment"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{score}","system":"http://unitsofmeasure.org","unit":"score","value":22}}],"warnings":[]}]}} +{"id":"assessment/HKScoredAssessmentTypeIdentifierPHQ9/-1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"assessment":{"score":-1,"type":"HKScoredAssessmentTypeIdentifierPHQ9"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"44261-6","display":"Patient Health Questionnaire 9 item (PHQ-9) total score [Reported]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKScoredAssessmentTypeIdentifierPHQ9"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:oDcWD3H5Nzbu6JTo-wqFh3Cy9CVrzpDhGlIjrS7oH-c"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zvmbhc8M7iZhYmhD0ZjaGmizzP3mtM_pBk5TV8yEVF0"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-phq9-assessment"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{score}","system":"http://unitsofmeasure.org","unit":"score","value":-1}}],"warnings":[]}]}} +{"id":"assessment/HKScoredAssessmentTypeIdentifierPHQ9/0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"assessment":{"score":0,"type":"HKScoredAssessmentTypeIdentifierPHQ9"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"44261-6","display":"Patient Health Questionnaire 9 item (PHQ-9) total score [Reported]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKScoredAssessmentTypeIdentifierPHQ9"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:oDcWD3H5Nzbu6JTo-wqFh3Cy9CVrzpDhGlIjrS7oH-c"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zvmbhc8M7iZhYmhD0ZjaGmizzP3mtM_pBk5TV8yEVF0"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-phq9-assessment"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{score}","system":"http://unitsofmeasure.org","unit":"score","value":0}}],"warnings":[]}]}} +{"id":"assessment/HKScoredAssessmentTypeIdentifierPHQ9/14","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"assessment":{"score":14,"type":"HKScoredAssessmentTypeIdentifierPHQ9"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"44261-6","display":"Patient Health Questionnaire 9 item (PHQ-9) total score [Reported]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKScoredAssessmentTypeIdentifierPHQ9"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:oDcWD3H5Nzbu6JTo-wqFh3Cy9CVrzpDhGlIjrS7oH-c"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zvmbhc8M7iZhYmhD0ZjaGmizzP3mtM_pBk5TV8yEVF0"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-phq9-assessment"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{score}","system":"http://unitsofmeasure.org","unit":"score","value":14}}],"warnings":[]}]}} +{"id":"assessment/HKScoredAssessmentTypeIdentifierPHQ9/27","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"assessment":{"score":27,"type":"HKScoredAssessmentTypeIdentifierPHQ9"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"44261-6","display":"Patient Health Questionnaire 9 item (PHQ-9) total score [Reported]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKScoredAssessmentTypeIdentifierPHQ9"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:oDcWD3H5Nzbu6JTo-wqFh3Cy9CVrzpDhGlIjrS7oH-c"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zvmbhc8M7iZhYmhD0ZjaGmizzP3mtM_pBk5TV8yEVF0"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-phq9-assessment"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{score}","system":"http://unitsofmeasure.org","unit":"score","value":27}}],"warnings":[]}]}} +{"id":"assessment/HKScoredAssessmentTypeIdentifierPHQ9/28","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"assessment":{"score":28,"type":"HKScoredAssessmentTypeIdentifierPHQ9"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"44261-6","display":"Patient Health Questionnaire 9 item (PHQ-9) total score [Reported]","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKScoredAssessmentTypeIdentifierPHQ9"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:oDcWD3H5Nzbu6JTo-wqFh3Cy9CVrzpDhGlIjrS7oH-c"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zvmbhc8M7iZhYmhD0ZjaGmizzP3mtM_pBk5TV8yEVF0"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-phq9-assessment"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{score}","system":"http://unitsofmeasure.org","unit":"score","value":28}}],"warnings":[]}]}} +{"id":"row/HKDataTypeIdentifierAudiogram","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"bare":{"sampleClass":"HKAudiogramSample","type":"HKDataTypeIdentifierAudiogram"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"unsupportedSourceType(GroveHealthKitFHIR.HealthKitSourceType.audiogram)","location":"HKSample.sampleType"}}} +{"id":"row/HKVisionPrescriptionTypeIdentifier","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"bare":{"sampleClass":"HKVisionPrescription","type":"HKVisionPrescriptionTypeIdentifier"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.platform-exclusive-source-type","error":"platformExclusiveSourceType(GroveHealthKitFHIR.HealthKitSourceType.visionPrescription)","location":"HKSample.sampleType"}}} +{"id":"row/HKMedicationDoseEventTypeIdentifierMedicationDoseEvent","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"bare":{"sampleClass":"HKMedicationDoseEvent","type":"HKMedicationDoseEventTypeIdentifierMedicationDoseEvent"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.platform-exclusive-source-type","error":"platformExclusiveSourceType(GroveHealthKitFHIR.HealthKitSourceType.medicationDoseEvent)","location":"HKSample.sampleType"}}} +{"id":"metadata/heart-rate-motion-context/absent","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"metadata/heart-rate-motion-context/0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeyHeartRateMotionContext":{"integer":0},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"HKMetadataKeyHeartRateMotionContext","display":"Heart Rate Motion Context","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-metadata-key"}]},"valueCodeableConcept":{"coding":[{"code":"not-set","display":"Not Set","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-heart-rate-motion-context"}]}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"metadata/heart-rate-motion-context/1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeyHeartRateMotionContext":{"integer":1},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"HKMetadataKeyHeartRateMotionContext","display":"Heart Rate Motion Context","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-metadata-key"}]},"valueCodeableConcept":{"coding":[{"code":"sedentary","display":"Sedentary","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-heart-rate-motion-context"}]}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"metadata/heart-rate-motion-context/2","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeyHeartRateMotionContext":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"HKMetadataKeyHeartRateMotionContext","display":"Heart Rate Motion Context","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-metadata-key"}]},"valueCodeableConcept":{"coding":[{"code":"active","display":"Active","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-heart-rate-motion-context"}]}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"metadata/heart-rate-motion-context/3","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeyHeartRateMotionContext":{"integer":3},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.heartRateMotionContext))","location":"HKSample.metadata[HKMetadataKeyHeartRateMotionContext]"}}} +{"id":"metadata/heart-rate-motion-context/-1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeyHeartRateMotionContext":{"integer":-1},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.heartRateMotionContext))","location":"HKSample.metadata[HKMetadataKeyHeartRateMotionContext]"}}} +{"id":"metadata/heart-rate-motion-context/string","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeyHeartRateMotionContext":{"string":"1"},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"metadata/heart-rate-motion-context/boolean","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeyHeartRateMotionContext":{"boolean":true},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"HKMetadataKeyHeartRateMotionContext","display":"Heart Rate Motion Context","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-metadata-key"}]},"valueCodeableConcept":{"coding":[{"code":"sedentary","display":"Sedentary","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-heart-rate-motion-context"}]}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"metadata/heart-rate-motion-context/double","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeyHeartRateMotionContext":{"double":1.5},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"HKMetadataKeyHeartRateMotionContext","display":"Heart Rate Motion Context","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-metadata-key"}]},"valueCodeableConcept":{"coding":[{"code":"sedentary","display":"Sedentary","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-heart-rate-motion-context"}]}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"metadata/insulin-delivery-reason/absent","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInsulinDelivery","unit":"IU","value":2.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.required-metadata-missing","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.insulinDelivery, GroveHealthKitFHIR.HealthKitValueFailure.requiredMetadataMissing(GroveHealthKitFHIR.HealthKitMetadataField.insulinDeliveryReason))","location":"HKSample.metadata[HKInsulinDeliveryReason]"}}} +{"id":"metadata/insulin-delivery-reason/1","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKInsulinDeliveryReason":{"integer":1},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInsulinDelivery","unit":"IU","value":2.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"insulin-delivery","display":"Insulin delivery","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"HKInsulinDeliveryReason","display":"Insulin Delivery Reason","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-metadata-key"}]},"valueCodeableConcept":{"coding":[{"code":"basal","display":"Basal","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-insulin-delivery-reason"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierInsulinDelivery"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Byoj5hiqvmTk7z-hmCOr5jq3YP_zWz0JSRV_AHfmQ6U"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:b8-BL0CQkqj9OeIPzbdXIjwHSvDlKCZjKAUiECAiKKE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-insulin-delivery"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"[iU]","system":"http://unitsofmeasure.org","unit":"IU","value":2.5}}],"warnings":[]}]}} +{"id":"metadata/insulin-delivery-reason/2","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKInsulinDeliveryReason":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInsulinDelivery","unit":"IU","value":2.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"insulin-delivery","display":"Insulin delivery","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"HKInsulinDeliveryReason","display":"Insulin Delivery Reason","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-metadata-key"}]},"valueCodeableConcept":{"coding":[{"code":"bolus","display":"Bolus","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-insulin-delivery-reason"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierInsulinDelivery"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Byoj5hiqvmTk7z-hmCOr5jq3YP_zWz0JSRV_AHfmQ6U"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:b8-BL0CQkqj9OeIPzbdXIjwHSvDlKCZjKAUiECAiKKE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-insulin-delivery"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"[iU]","system":"http://unitsofmeasure.org","unit":"IU","value":2.5}}],"warnings":[]}]}} +{"id":"metadata/insulin-delivery-reason/0","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKInsulinDeliveryReason":{"integer":0},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInsulinDelivery","unit":"IU","value":2.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.insulinDelivery, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.insulinDeliveryReason))","location":"HKSample.metadata[HKInsulinDeliveryReason]"}}} +{"id":"metadata/insulin-delivery-reason/3","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKInsulinDeliveryReason":{"integer":3},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInsulinDelivery","unit":"IU","value":2.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.insulinDelivery, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.insulinDeliveryReason))","location":"HKSample.metadata[HKInsulinDeliveryReason]"}}} +{"id":"metadata/insulin-delivery-reason/string","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKInsulinDeliveryReason":{"string":"1"},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInsulinDelivery","unit":"IU","value":2.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.required-metadata-missing","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.insulinDelivery, GroveHealthKitFHIR.HealthKitValueFailure.requiredMetadataMissing(GroveHealthKitFHIR.HealthKitMetadataField.insulinDeliveryReason))","location":"HKSample.metadata[HKInsulinDeliveryReason]"}}} +{"id":"metadata/insulin-delivery-reason/boolean","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKInsulinDeliveryReason":{"boolean":true},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInsulinDelivery","unit":"IU","value":2.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"insulin-delivery","display":"Insulin delivery","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"HKInsulinDeliveryReason","display":"Insulin Delivery Reason","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-metadata-key"}]},"valueCodeableConcept":{"coding":[{"code":"basal","display":"Basal","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-insulin-delivery-reason"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierInsulinDelivery"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Byoj5hiqvmTk7z-hmCOr5jq3YP_zWz0JSRV_AHfmQ6U"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:b8-BL0CQkqj9OeIPzbdXIjwHSvDlKCZjKAUiECAiKKE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-insulin-delivery"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"[iU]","system":"http://unitsofmeasure.org","unit":"IU","value":2.5}}],"warnings":[]}]}} +{"id":"metadata/insulin-delivery-reason/double","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKInsulinDeliveryReason":{"double":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInsulinDelivery","unit":"IU","value":2.5}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"insulin-delivery","display":"Insulin delivery","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"component":[{"code":{"coding":[{"code":"HKInsulinDeliveryReason","display":"Insulin Delivery Reason","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-metadata-key"}]},"valueCodeableConcept":{"coding":[{"code":"bolus","display":"Bolus","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-insulin-delivery-reason"}]}}],"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierInsulinDelivery"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Byoj5hiqvmTk7z-hmCOr5jq3YP_zWz0JSRV_AHfmQ6U"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:b8-BL0CQkqj9OeIPzbdXIjwHSvDlKCZjKAUiECAiKKE"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-insulin-delivery"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"[iU]","system":"http://unitsofmeasure.org","unit":"IU","value":2.5}}],"warnings":[]}]}} +{"id":"metadata/menstrual-cycle-start/absent","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMenstrualFlow","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.required-metadata-missing","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.menstrualFlow, GroveHealthKitFHIR.HealthKitValueFailure.requiredMetadataMissing(GroveHealthKitFHIR.HealthKitMetadataField.menstrualCycleStart))","location":"HKSample.metadata[HKMenstrualCycleStart]"}}} +{"id":"metadata/menstrual-cycle-start/true","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMenstrualCycleStart":{"boolean":true},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMenstrualFlow","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"menstruation-flow","display":"Menstruation flow","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"menstrual-cycle-start","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"cycle-start","display":"Cycle start","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-menstrual-cycle-start"}]}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierMenstrualFlow"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zOQPZidTQvTfQKlYbhtjlfByibOVb39p77pRY-BIgRs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:i2VZaK7j7kjlmoihuJaK8_l9eGPvDFPEdHfePQSIu_8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-menstruation-flow","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"light","display":"Light","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-menstruation-flow"},{"code":"light","display":"Light","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-vaginal-bleeding"}]}}],"warnings":[]}]}} +{"id":"metadata/menstrual-cycle-start/false","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMenstrualCycleStart":{"boolean":false},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMenstrualFlow","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"menstruation-flow","display":"Menstruation flow","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"component":[{"code":{"coding":[{"code":"menstrual-cycle-start","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"valueCodeableConcept":{"coding":[{"code":"not-cycle-start","display":"Not cycle start","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-menstrual-cycle-start"}]}}],"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierMenstrualFlow"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zOQPZidTQvTfQKlYbhtjlfByibOVb39p77pRY-BIgRs"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:i2VZaK7j7kjlmoihuJaK8_l9eGPvDFPEdHfePQSIu_8"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-menstruation-flow","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"light","display":"Light","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-menstruation-flow"},{"code":"light","display":"Light","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-vaginal-bleeding"}]}}],"warnings":[]}]}} +{"id":"metadata/menstrual-cycle-start/integer-1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMenstrualCycleStart":{"integer":1},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMenstrualFlow","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.menstrualFlow, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.menstrualCycleStart))","location":"HKSample.metadata[HKMenstrualCycleStart]"}}} +{"id":"metadata/menstrual-cycle-start/integer-0","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMenstrualCycleStart":{"integer":0},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMenstrualFlow","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.menstrualFlow, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.menstrualCycleStart))","location":"HKSample.metadata[HKMenstrualCycleStart]"}}} +{"id":"metadata/menstrual-cycle-start/integer-2","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMenstrualCycleStart":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMenstrualFlow","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.menstrualFlow, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.menstrualCycleStart))","location":"HKSample.metadata[HKMenstrualCycleStart]"}}} +{"id":"metadata/menstrual-cycle-start/string","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMenstrualCycleStart":{"string":"true"},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMenstrualFlow","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.menstrualFlow, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.menstrualCycleStart))","location":"HKSample.metadata[HKMenstrualCycleStart]"}}} +{"id":"metadata/menstrual-cycle-start/double","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMenstrualCycleStart":{"double":1},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMenstrualFlow","value":2}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.menstrualFlow, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.menstrualCycleStart))","location":"HKSample.metadata[HKMenstrualCycleStart]"}}} +{"id":"metadata/sexual-activity-protection/absent","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSexualActivity","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"sexual-activity","display":"Sexual activity","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSexualActivity"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:lPEB9lIVwzwL_XQhftEDx4-95fgZuyOhCg1cfxowq3I"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:FI4pGDsSw5sWnaPieuPeuqDvYzsl-wNnSQ_onDCux1I"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-sexual-activity","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"unknown","display":"Unknown","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-sexual-activity"}]}}],"warnings":[]}]}} +{"id":"metadata/sexual-activity-protection/true","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKSexualActivityProtectionUsed":{"boolean":true},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSexualActivity","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"sexual-activity","display":"Sexual activity","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSexualActivity"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:lPEB9lIVwzwL_XQhftEDx4-95fgZuyOhCg1cfxowq3I"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:FI4pGDsSw5sWnaPieuPeuqDvYzsl-wNnSQ_onDCux1I"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-sexual-activity","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"protected","display":"Protection used","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-sexual-activity"}]}}],"warnings":[]}]}} +{"id":"metadata/sexual-activity-protection/false","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKSexualActivityProtectionUsed":{"boolean":false},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSexualActivity","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"code":{"coding":[{"code":"sexual-activity","display":"Sexual activity","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierSexualActivity"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:lPEB9lIVwzwL_XQhftEDx4-95fgZuyOhCg1cfxowq3I"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:FI4pGDsSw5sWnaPieuPeuqDvYzsl-wNnSQ_onDCux1I"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-sexual-activity","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"unprotected","display":"Protection not used","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-sexual-activity"}]}}],"warnings":[]}]}} +{"id":"metadata/sexual-activity-protection/integer-1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKSexualActivityProtectionUsed":{"integer":1},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSexualActivity","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sexualActivity, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.sexualActivityProtectionUsed))","location":"HKSample.metadata[HKSexualActivityProtectionUsed]"}}} +{"id":"metadata/sexual-activity-protection/integer-2","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKSexualActivityProtectionUsed":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSexualActivity","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sexualActivity, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.sexualActivityProtectionUsed))","location":"HKSample.metadata[HKSexualActivityProtectionUsed]"}}} +{"id":"metadata/sexual-activity-protection/string","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKSexualActivityProtectionUsed":{"string":"yes"},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSexualActivity","value":0}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sexualActivity, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.sexualActivityProtectionUsed))","location":"HKSample.metadata[HKSexualActivityProtectionUsed]"}}} +{"id":"metadata/was-user-entered/true","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"},"HKWasUserEntered":{"boolean":true}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"},{"url":"https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-method","valueCoding":{"code":"manual-entry","display":"Manual entry","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-recording-method"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"metadata/was-user-entered/false","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"},"HKWasUserEntered":{"boolean":false}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"metadata/was-user-entered/integer-1","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"},"HKWasUserEntered":{"integer":1}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"metadata/was-user-entered/integer-2","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"},"HKWasUserEntered":{"integer":2}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"metadata/was-user-entered/string","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"},"HKWasUserEntered":{"string":"true"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"metadata/was-user-entered/heartbeat-series","input":{"convert":{"source":{"context":"plain","end":1787005802,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"},"HKWasUserEntered":{"boolean":true}},"record":{"heartbeatSeries":{"beats":[{"gap":false,"offset":0},{"gap":false,"offset":0.84},{"gap":true,"offset":1.71}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"text/csv","data":"dGltZXN0YW1wLHByZWNlZGVkQnlHYXAKMTc4NzAwNTgwMCwwCjE3ODcwMDU4MDAuODQsMAoxNzg3MDA1ODAxLjcxLDEK","hash":"PznINcuYWCKX6a0UnspSBwERECs=","size":69,"title":"Heartbeat series beat intervals"},"format":{"code":"beat-interval-series","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierHeartbeatSeries"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:iX--MzI0MGrvyapHnU73sSiP2C1nLB-KvIvZjrB-afY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MzKITWeje_hGgybDCN8aIdK4mrEiMwsNqEpreiY1qqw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:EXgECvaw4yJ81Lg6Vw_zCLiEPcJtNX9URuDItFw_J8A"}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-recording-document","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-recording-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"beat-interval-series","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}]}}],"warnings":[]}]}} +{"id":"metadata/sync/pair","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeySyncIdentifier":{"string":"sync-abc"},"HKMetadataKeySyncVersion":{"integer":3},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"foreign"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"},{"url":"https://grovealliance.org/fhir/mobile/StructureDefinition/grove-writer-record-version","valueString":"3"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/writer-record/test/1","type":{"coding":[{"code":"writer-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vIfSIjXEDH2sYfmrl7Plzyh6_3t3FdXKG5O2EZe5vpQ"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"metadata/sync/identifier-only","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeySyncIdentifier":{"string":"sync-abc"},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"foreign"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.invalidMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.syncVersion))","location":"HKSample.metadata[HKMetadataKeySyncVersion]"}}} +{"id":"metadata/sync/version-only","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeySyncVersion":{"integer":3},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"foreign"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.invalidMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.syncIdentifier))","location":"HKSample.metadata[HKMetadataKeySyncIdentifier]"}}} +{"id":"metadata/sync/empty-identifier","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeySyncIdentifier":{"string":""},"HKMetadataKeySyncVersion":{"integer":3},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"foreign"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.invalidMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.syncIdentifier))","location":"HKSample.metadata[HKMetadataKeySyncIdentifier]"}}} +{"id":"metadata/sync/identifier-number","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeySyncIdentifier":{"integer":7},"HKMetadataKeySyncVersion":{"integer":3},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"foreign"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.invalidMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.syncIdentifier))","location":"HKSample.metadata[HKMetadataKeySyncIdentifier]"}}} +{"id":"metadata/sync/version-string","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeySyncIdentifier":{"string":"sync-abc"},"HKMetadataKeySyncVersion":{"string":"3"},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"foreign"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.invalidMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.syncVersion))","location":"HKSample.metadata[HKMetadataKeySyncVersion]"}}} +{"id":"metadata/sync/version-boolean","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeySyncIdentifier":{"string":"sync-abc"},"HKMetadataKeySyncVersion":{"boolean":true},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"foreign"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.invalidMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.syncVersion))","location":"HKSample.metadata[HKMetadataKeySyncVersion]"}}} +{"id":"metadata/sync/version-negative","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeySyncIdentifier":{"string":"sync-abc"},"HKMetadataKeySyncVersion":{"integer":-1},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"foreign"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.invalidMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.syncVersion))","location":"HKSample.metadata[HKMetadataKeySyncVersion]"}}} +{"id":"metadata/sync/version-fractional","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeySyncIdentifier":{"string":"sync-abc"},"HKMetadataKeySyncVersion":{"double":2.5},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"foreign"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.invalidMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.syncVersion))","location":"HKSample.metadata[HKMetadataKeySyncVersion]"}}} +{"id":"metadata/sync/version-zero","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeySyncIdentifier":{"string":"sync-abc"},"HKMetadataKeySyncVersion":{"integer":0},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"foreign"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"},{"url":"https://grovealliance.org/fhir/mobile/StructureDefinition/grove-writer-record-version","valueString":"0"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/writer-record/test/1","type":{"coding":[{"code":"writer-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vIfSIjXEDH2sYfmrl7Plzyh6_3t3FdXKG5O2EZe5vpQ"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"metadata/sync/version-integral-double","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeySyncIdentifier":{"string":"sync-abc"},"HKMetadataKeySyncVersion":{"double":3},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"foreign"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"},{"url":"https://grovealliance.org/fhir/mobile/StructureDefinition/grove-writer-record-version","valueString":"3"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/writer-record/test/1","type":{"coding":[{"code":"writer-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:vIfSIjXEDH2sYfmrl7Plzyh6_3t3FdXKG5O2EZe5vpQ"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"metadata/sync/pair-without-writer","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeySyncIdentifier":{"string":"sync-abc"},"HKMetadataKeySyncVersion":{"integer":3},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"metadata/unmodeled/heart-rate/external-uuid","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKExternalUUID":{"string":"external-1"},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":["mobile-omission.unmodeled-metadata(HKExternalUUID)"]}]}} +{"id":"metadata/unmodeled/heart-rate/custom","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"},"org.example.flag":{"boolean":true}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":["mobile-omission.unmodeled-metadata(org.example.flag)"]}]}} +{"id":"metadata/unmodeled/heart-rate/both","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKExternalUUID":{"string":"external-1"},"HKTimeZone":{"string":"America/Los_Angeles"},"org.example.flag":{"boolean":true}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":["mobile-omission.unmodeled-metadata(HKExternalUUID,org.example.flag)"]}]}} +{"id":"metadata/unmodeled/heart-rate/menstrual-cycle-start","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMenstrualCycleStart":{"boolean":true},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"metadata/unmodeled/heart-rate/insulin-delivery-reason","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKInsulinDeliveryReason":{"integer":1},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"metadata/unmodeled/heart-rate/ecg-algorithm-version","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"metadata/unmodeled/heart-rate/sexual-activity-protection","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKSexualActivityProtectionUsed":{"boolean":true},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"metadata/unmodeled/body-mass/heart-rate-motion-context","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeyHeartRateMotionContext":{"integer":1},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierBodyMass","unit":"kg","value":70}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"29463-7","display":"Body weight","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierBodyMass"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:PB6bQq5G5_XFkWF6zQjzHCp52oSs2Yz_xikZvGGGduU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"kg","system":"http://unitsofmeasure.org","unit":"kg","value":70}}],"warnings":[]}]}} +{"id":"metadata/unmodeled/step-count/insulin-delivery-reason","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKInsulinDeliveryReason":{"integer":1},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"category":[{"coding":[{"code":"activity","display":"Activity","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"step-count-total","display":"Step count total","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:31:00-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierStepCount"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:xBQTgoBEq1Gm0qYZwtYwNwLReW65lCU5F5RcFbF641M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"{steps}","system":"http://unitsofmeasure.org","unit":"steps","value":120}}],"warnings":[]}]}} +{"id":"metadata/unmodeled/heartbeat-series/custom","input":{"convert":{"source":{"context":"plain","end":1787005802,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"},"org.example.flag":{"boolean":true}},"record":{"heartbeatSeries":{"beats":[{"gap":false,"offset":0},{"gap":false,"offset":0.84},{"gap":true,"offset":1.71}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"text/csv","data":"dGltZXN0YW1wLHByZWNlZGVkQnlHYXAKMTc4NzAwNTgwMCwwCjE3ODcwMDU4MDAuODQsMAoxNzg3MDA1ODAxLjcxLDEK","hash":"PznINcuYWCKX6a0UnspSBwERECs=","size":69,"title":"Heartbeat series beat intervals"},"format":{"code":"beat-interval-series","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierHeartbeatSeries"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:iX--MzI0MGrvyapHnU73sSiP2C1nLB-KvIvZjrB-afY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MzKITWeje_hGgybDCN8aIdK4mrEiMwsNqEpreiY1qqw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:EXgECvaw4yJ81Lg6Vw_zCLiEPcJtNX9URuDItFw_J8A"}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-recording-document","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-recording-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"beat-interval-series","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}]}}],"warnings":["mobile-omission.unmodeled-metadata(org.example.flag)"]}]}} +{"id":"metadata/unmodeled/heartbeat-series/menstrual-cycle-start","input":{"convert":{"source":{"context":"plain","end":1787005802,"metadata":{"HKMenstrualCycleStart":{"boolean":true},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"heartbeatSeries":{"beats":[{"gap":false,"offset":0},{"gap":false,"offset":0.84},{"gap":true,"offset":1.71}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"text/csv","data":"dGltZXN0YW1wLHByZWNlZGVkQnlHYXAKMTc4NzAwNTgwMCwwCjE3ODcwMDU4MDAuODQsMAoxNzg3MDA1ODAxLjcxLDEK","hash":"PznINcuYWCKX6a0UnspSBwERECs=","size":69,"title":"Heartbeat series beat intervals"},"format":{"code":"beat-interval-series","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierHeartbeatSeries"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:iX--MzI0MGrvyapHnU73sSiP2C1nLB-KvIvZjrB-afY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MzKITWeje_hGgybDCN8aIdK4mrEiMwsNqEpreiY1qqw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:EXgECvaw4yJ81Lg6Vw_zCLiEPcJtNX9URuDItFw_J8A"}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-recording-document","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-recording-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"beat-interval-series","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}]}}],"warnings":[]}]}} +{"id":"metadata/unmodeled/heartbeat-series/zone-only","input":{"convert":{"source":{"context":"plain","end":1787005802,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"heartbeatSeries":{"beats":[{"gap":false,"offset":0},{"gap":false,"offset":0.84},{"gap":true,"offset":1.71}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"text/csv","data":"dGltZXN0YW1wLHByZWNlZGVkQnlHYXAKMTc4NzAwNTgwMCwwCjE3ODcwMDU4MDAuODQsMAoxNzg3MDA1ODAxLjcxLDEK","hash":"PznINcuYWCKX6a0UnspSBwERECs=","size":69,"title":"Heartbeat series beat intervals"},"format":{"code":"beat-interval-series","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierHeartbeatSeries"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:iX--MzI0MGrvyapHnU73sSiP2C1nLB-KvIvZjrB-afY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MzKITWeje_hGgybDCN8aIdK4mrEiMwsNqEpreiY1qqw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:EXgECvaw4yJ81Lg6Vw_zCLiEPcJtNX9URuDItFw_J8A"}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-recording-document","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-recording-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"beat-interval-series","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}]}}],"warnings":[]}]}} +{"id":"metadata/device/watch","input":{"convert":{"source":{"context":"plain","device":"watch","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"device":{"reference":"urn:uuid:f25c9573-130f-523c-8aa0-0f06d8dbf989"},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"metadata/device/watch-without-unit-token","input":{"convert":{"source":{"context":"plain","device":"watchWithoutUnitToken","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"_effectiveDateTime":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"effectiveDateTime":"2026-08-17T15:30:00-07:00","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKQuantityTypeIdentifierHeartRate"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:VVvJDi4nChkPklE2zNFnjsI8R2EESNY6ZmkQjLVNsjQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":["mobile-omission.recording-device(Apple Watch)"]}]}} +{"id":"precedence/zone-before-value","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"Not/A-Time-Zone"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.timeZone))","location":"HKSample.metadata[HKTimeZone]"}}} +{"id":"precedence/zone-before-motion-context","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeyHeartRateMotionContext":{"integer":3},"HKTimeZone":{"string":"Not/A-Time-Zone"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.timeZone))","location":"HKSample.metadata[HKTimeZone]"}}} +{"id":"precedence/value-before-motion-context","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeyHeartRateMotionContext":{"integer":3},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"precedence/effective-before-value","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stepCount, GroveHealthKitFHIR.HealthKitValueFailure.effectivePeriodInvalid)","location":"HKSample.startDate"}}} +{"id":"precedence/zone-before-effective","input":{"convert":{"source":{"context":"plain","end":1787005740,"metadata":{"HKTimeZone":{"string":"Not/A-Time-Zone"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierStepCount","unit":"count","value":120}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.stepCount, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.timeZone))","location":"HKSample.metadata[HKTimeZone]"}}} +{"id":"precedence/value-before-protection","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKSexualActivityProtectionUsed":{"string":"yes"},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSexualActivity","value":1}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sexualActivity, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(1))","location":"HKSample.value"}}} +{"id":"precedence/value-before-cycle-start","input":{"convert":{"source":{"context":"plain","end":1787005860,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierMenstrualFlow","value":9}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.menstrualFlow, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(9))","location":"HKSample.value"}}} +{"id":"precedence/value-before-insulin-reason","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierInsulinDelivery","unit":"IU","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.insulinDelivery, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"precedence/value-before-sync","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeySyncIdentifier":{"string":"sync-abc"},"HKMetadataKeySyncVersion":{"string":"3"},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":"NaN"}},"start":1787005800,"writer":"foreign"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"precedence/motion-context-before-sync","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKMetadataKeyHeartRateMotionContext":{"integer":3},"HKMetadataKeySyncIdentifier":{"string":"sync-abc"},"HKMetadataKeySyncVersion":{"string":"3"},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":72}},"start":1787005800,"writer":"foreign"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.heartRateMotionContext))","location":"HKSample.metadata[HKMetadataKeyHeartRateMotionContext]"}}} +{"id":"precedence/zone-before-missing-member","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"Not/A-Time-Zone"}},"record":{"correlation":{"members":[{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":80}],"type":"HKCorrelationTypeIdentifierBloodPressure"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bloodPressure, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.timeZone))","location":"HKSample.metadata[HKTimeZone]"}}} +{"id":"precedence/first-member-first","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"correlation":{"members":[{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureSystolic","unit":"mmHg","value":"NaN"},{"metadata":{},"type":"HKQuantityTypeIdentifierBloodPressureDiastolic","unit":"mmHg","value":-1}],"type":"HKCorrelationTypeIdentifierBloodPressure"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.bloodPressure, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"precedence/effective-before-value-year-10000","input":{"convert":{"source":{"context":"plain","end":253402300800,"metadata":{},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":"NaN"}},"start":253402300800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"precedence/effective-before-category-value","input":{"convert":{"source":{"context":"plain","end":1787005740,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"category":{"type":"HKCategoryTypeIdentifierSleepAnalysis","value":9}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.sleepAnalysis, GroveHealthKitFHIR.HealthKitValueFailure.effectivePeriodInvalid)","location":"HKSample.startDate"}}} +{"id":"precedence/zone-before-workout-duration","input":{"convert":{"source":{"context":"plain","end":1787009400,"metadata":{"HKTimeZone":{"string":"Not/A-Time-Zone"}},"record":{"workout":{"activity":37,"duration":"NaN","statistics":[]}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.workout, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.timeZone))","location":"HKSample.metadata[HKTimeZone]"}}} +{"id":"precedence/zone-before-assessment-score","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"Not/A-Time-Zone"}},"record":{"assessment":{"score":99,"type":"HKScoredAssessmentTypeIdentifierGAD7"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.gad7, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.timeZone))","location":"HKSample.metadata[HKTimeZone]"}}} +{"id":"precedence/empty-series-before-sync","input":{"convert":{"source":{"context":"plain","end":1787005802,"metadata":{"HKMetadataKeySyncIdentifier":{"string":"sync-abc"},"HKMetadataKeySyncVersion":{"string":"3"},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"heartbeatSeries":{"beats":[]}},"start":1787005800,"writer":"foreign"}}},"output":{"refused":{"code":"mobile-input.empty-recording-series","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartbeatSeries, GroveHealthKitFHIR.HealthKitValueFailure.emptyRecordingSeries)","location":"HKSample"}}} +{"id":"precedence/value-before-unmodeled-warning","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"},"org.example.flag":{"boolean":true}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"precedence/value-before-device-omission","input":{"convert":{"source":{"context":"plain","device":"watchWithoutUnitToken","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"quantity":{"type":"HKQuantityTypeIdentifierHeartRate","unit":"count/min","value":"NaN"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartRate, GroveHealthKitFHIR.HealthKitValueFailure.shapeInvalid)","location":"HKSample.value"}}} +{"id":"electrocardiogram/row","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"none"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"sinusRhythm","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"electrocardiogram/classification/0","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":0,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"none"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"notSet","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"electrocardiogram/classification/2","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":2,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"none"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"atrialFibrillation","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"electrocardiogram/classification/3","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":3,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"none"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"inconclusiveLowHeartRate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"electrocardiogram/classification/4","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":4,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"none"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"inconclusiveHighHeartRate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"electrocardiogram/classification/5","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":5,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"none"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"inconclusivePoorReading","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"electrocardiogram/classification/6","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":6,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"none"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"inconclusiveOther","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"electrocardiogram/classification/100","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":100,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"none"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"unrecognized","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"electrocardiogram/classification/99","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":99,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.unsupportedClassification(99))","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/symptoms-status/0","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":0,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"notSet"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"sinusRhythm","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"electrocardiogram/symptoms-status/99","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":99,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.unsupportedSymptomsStatus(99))","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/average-heart-rate/none","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"none"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"sinusRhythm","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}}],"warnings":[]}]}} +{"id":"electrocardiogram/average-heart-rate/fraction","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72.5,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"none"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"sinusRhythm","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72.5}}],"warnings":[]}]}} +{"id":"electrocardiogram/average-heart-rate/nan","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":"NaN","classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.invalidAverageHeartRate)","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/average-heart-rate/zero","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":0,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"none"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"sinusRhythm","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":0}}],"warnings":[]}]}} +{"id":"electrocardiogram/average-heart-rate/tiny","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":1e-07,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"none"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"sinusRhythm","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":0.0000001}}],"warnings":[]}]}} +{"id":"electrocardiogram/sampling-frequency/none","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"none"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"sinusRhythm","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"electrocardiogram/sampling-frequency/mismatch","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":250,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.samplingFrequencyMismatch)","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/sampling-frequency/zero","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":0,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.invalidSamplingFrequency)","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/sampling-frequency/nan","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":"NaN","symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.invalidSamplingFrequency)","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/sampling-frequency/negative","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":-500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.invalidSamplingFrequency)","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/sampling-frequency/near","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":499.99,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.samplingFrequencyMismatch)","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/count/zero","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":0,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.invalidReportedVoltageCount(0))","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/count/mismatch","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":3,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.voltageCountMismatch(reported: 3, supplied: 4))","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/count/one","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":1,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.insufficientVoltageMeasurements)","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/offsets/negative","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":-0.002},{"millivolts":0.25,"offset":0},{"millivolts":-0.125,"offset":0.002},{"millivolts":0,"offset":0.004}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.invalidOffset(index: 0))","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/offsets/repeated","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.25},{"millivolts":-0.125,"offset":0.252},{"millivolts":0,"offset":0.254}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.invalidOffset(index: 1))","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/offsets/non-uniform","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.255},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.nonUniformOffset(index: 2))","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/offsets/nan","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":"NaN"},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.invalidOffset(index: 1))","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/voltages/nan","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":"NaN","offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.invalidLeadVoltage(index: 1))","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/voltages/missing-lead","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.missingLeadVoltage(index: 2))","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/voltages/tiny","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":1e-07,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.0000001 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"none"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"sinusRhythm","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"electrocardiogram/voltages/huge","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":1e+21,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 1000000000000000000000 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"none"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"sinusRhythm","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"electrocardiogram/symptoms/one","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[{"ordinal":225,"type":"HKCategoryTypeIdentifierChestTightnessOrPain","value":2}],"symptomsStatus":2,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"present"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}}],"hasMember":[{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:6buMoRGt7bhQEKXTUGzTlPR2iqP6uo-5HSyFotQvk6M"},"type":"Observation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"sinusRhythm","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]},{"outputs":[{"code":{"coding":[{"code":"symptom-chest-tightness-or-pain","display":"Chest tightness or pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierChestTightnessOrPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:FhIVcBI-67QHzPdKEM59cCmAxBNQ63ABI6Gx6QLpxSA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:6buMoRGt7bhQEKXTUGzTlPR2iqP6uo-5HSyFotQvk6M"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-chest-tightness-or-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"electrocardiogram/symptoms/two-types","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[{"ordinal":226,"type":"HKCategoryTypeIdentifierFatigue","value":2},{"ordinal":225,"type":"HKCategoryTypeIdentifierChestTightnessOrPain","value":3}],"symptomsStatus":2,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"present"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}}],"hasMember":[{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:6buMoRGt7bhQEKXTUGzTlPR2iqP6uo-5HSyFotQvk6M"},"type":"Observation"},{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zc23Io-At40ZW5QN_Qb9v9L7XLTQUySep6cSNT3UZLs"},"type":"Observation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"sinusRhythm","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]},{"outputs":[{"code":{"coding":[{"code":"symptom-chest-tightness-or-pain","display":"Chest tightness or pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierChestTightnessOrPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:FhIVcBI-67QHzPdKEM59cCmAxBNQ63ABI6Gx6QLpxSA"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:6buMoRGt7bhQEKXTUGzTlPR2iqP6uo-5HSyFotQvk6M"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-chest-tightness-or-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"moderate","display":"Moderate","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]},{"outputs":[{"code":{"coding":[{"code":"symptom-fatigue","display":"Fatigue","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierFatigue"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:GfuKpwBJutIxIrLcUw_ev7xeJSb3hYPU2A4nlbbdNec"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zc23Io-At40ZW5QN_Qb9v9L7XLTQUySep6cSNT3UZLs"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-fatigue"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"electrocardiogram/symptoms/same-type","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[{"ordinal":228,"type":"HKCategoryTypeIdentifierChestTightnessOrPain","value":2},{"ordinal":227,"type":"HKCategoryTypeIdentifierChestTightnessOrPain","value":4}],"symptomsStatus":2,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"present"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}}],"hasMember":[{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2_zdEPlpkTBW_BbbH4WhAK3GIH_XkGVKl_WVtwLzAFM"},"type":"Observation"},{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:A6xoQt7WXbPrIi04CXBqQYFWMlX6oSrhld5LQNeuKlQ"},"type":"Observation"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"sinusRhythm","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]},{"outputs":[{"code":{"coding":[{"code":"symptom-chest-tightness-or-pain","display":"Chest tightness or pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierChestTightnessOrPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:iZ-jdeUhllchC1xWhjeIJW8fRXqmNNn0mQWfE854aDw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2_zdEPlpkTBW_BbbH4WhAK3GIH_XkGVKl_WVtwLzAFM"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-chest-tightness-or-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"severe","display":"Severe","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]},{"outputs":[{"code":{"coding":[{"code":"symptom-chest-tightness-or-pain","display":"Chest tightness or pain","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement"}]},"effectivePeriod":{"_end":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"_start":{"extension":[{"url":"http://hl7.org/fhir/StructureDefinition/timezone","valueCode":"America/Los_Angeles"}]},"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKCategoryTypeIdentifierChestTightnessOrPain"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:L_ygnIrugp7BIcJmOIZVmmzkaptPu-wJ7mNGd_L49tI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:A6xoQt7WXbPrIi04CXBqQYFWMlX6oSrhld5LQNeuKlQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-chest-tightness-or-pain"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueCodeableConcept":{"coding":[{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/grove-symptom-severity"},{"code":"mild","display":"Mild","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-symptom-severity"}]}}],"warnings":[]}]}} +{"id":"electrocardiogram/symptoms/unsupported-type","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[{"ordinal":225,"type":"HKCategoryTypeIdentifierHeadache","value":2}],"symptomsStatus":2,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.unsupportedSymptomType(\"HKCategoryTypeIdentifierHeadache\"))","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/symptoms/duplicate-source","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[{"ordinal":225,"type":"HKCategoryTypeIdentifierChestTightnessOrPain","value":2},{"ordinal":225,"type":"HKCategoryTypeIdentifierFatigue","value":2}],"symptomsStatus":2,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.duplicateSymptomSource(3A7E5C10-0000-4000-8000-0000000000E1))","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/symptoms/unexpected","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[{"ordinal":225,"type":"HKCategoryTypeIdentifierChestTightnessOrPain","value":2}],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.unexpectedSymptoms)","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/symptoms/required","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":2,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.symptomsRequired)","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/symptoms/invalid-value","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[{"ordinal":225,"type":"HKCategoryTypeIdentifierChestTightnessOrPain","value":9}],"symptomsStatus":2,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.electrocardiogram, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedValue(9))","location":"HKSample.value"}}} +{"id":"electrocardiogram/symptoms/context-missing","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptomContexts":0,"symptoms":[{"ordinal":225,"type":"HKCategoryTypeIdentifierChestTightnessOrPain","value":2}],"symptomsStatus":2,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.symptomContextCountMismatch(symptoms: 1, contexts: 0))","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/precedence/symptoms-before-classification","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":99,"reportedCount":4,"samplingFrequency":500,"symptoms":[{"ordinal":225,"type":"HKCategoryTypeIdentifierHeadache","value":2}],"symptomsStatus":2,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.unsupportedSymptomType(\"HKCategoryTypeIdentifierHeadache\"))","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/precedence/count-before-average-heart-rate","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":"NaN","classification":1,"reportedCount":3,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.voltageCountMismatch(reported: 3, supplied: 4))","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/zone/none","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T22:30:00.256Z","start":"2026-08-17T22:30:00.25Z"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"none"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T22:30:30Z","start":"2026-08-17T22:30:00Z"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"sinusRhythm","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T22:30:00.256Z","start":"2026-08-17T22:30:00.25Z"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":["mobile-omission.source-offset@Observation.effectivePeriod.start","mobile-omission.source-offset@Observation.effectivePeriod.end"]}]}} +{"id":"electrocardiogram/zone/invalid","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"Not/A-Time-Zone"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.electrocardiogram, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.timeZone))","location":"HKSample.metadata[HKTimeZone]"}}} +{"id":"electrocardiogram/zone/kathmandu","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"Asia/Kathmandu"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-18T04:15:00.256+05:45","start":"2026-08-18T04:15:00.25+05:45"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"none"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-18T04:15:30+05:45","start":"2026-08-18T04:15:00+05:45"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"sinusRhythm","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-18T04:15:00.256+05:45","start":"2026-08-18T04:15:00.25+05:45"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"electrocardiogram/algorithm-version/absent","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"none"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"sinusRhythm","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"electrocardiogram/algorithm-version/1","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":1},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"none"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"sinusRhythm","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version1","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"electrocardiogram/algorithm-version/3","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":3},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.unsupportedAlgorithmVersion(3))","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/algorithm-version/string","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"string":"2"},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"none"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"sinusRhythm","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"electrocardiogram/algorithm-version/double","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"double":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"none"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"sinusRhythm","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"electrocardiogram/user-entered","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"},"HKWasUserEntered":{"boolean":true}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"none"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}},{"url":"https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-method","valueCoding":{"code":"manual-entry","display":"Manual entry","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-recording-method"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"sinusRhythm","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-method","valueCoding":{"code":"manual-entry","display":"Manual entry","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-recording-method"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"electrocardiogram/reversed","input":{"convert":{"source":{"context":"plain","end":1787005770,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.invalidSourcePeriod)","location":"HKElectrocardiogram"}}} +{"id":"electrocardiogram/linked","input":{"convert":{"source":{"context":"linked","device":"watch","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"America/Los_Angeles"},"HKWasUserEntered":{"boolean":true}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":4,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"code":{"coding":[{"code":"11524-6","display":"EKG study","system":"http://loinc.org"}]},"component":[{"code":{"coding":[{"code":"131329","display":"MDC_ECG_ELEC_POTL_I","system":"urn:iso:std:iso:11073:10101"}]},"valueSampledData":{"data":"0.125 0.25 -0.125 0","dimensions":1,"origin":{"code":"mV","system":"http://unitsofmeasure.org","unit":"mV","value":0},"period":2}}],"device":{"reference":"urn:uuid:f25c9573-130f-523c-8aa0-0f06d8dbf989"},"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-symptoms-status","valueCode":"none"},{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-source-period","valuePeriod":{"end":"2026-08-17T15:30:30-07:00","start":"2026-08-17T15:30:00-07:00"}},{"url":"https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-method","valueCoding":{"code":"manual-entry","display":"Manual entry","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-recording-method"}},{"url":"http://hl7.org/fhir/StructureDefinition/observation-gatewayDevice","valueReference":{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}},{"url":"http://hl7.org/fhir/StructureDefinition/workflow-researchStudy","valueReference":{"reference":"urn:uuid:38bde736-9a38-596d-82f1-f3e0517c608d","type":"ResearchStudy"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0"}],"interpretation":[{"coding":[{"code":"sinusRhythm","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-classification"}]}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]},"method":{"coding":[{"code":"version2","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-ecg-algorithm-version"}]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"}},{"category":[{"coding":[{"code":"vital-signs","display":"Vital Signs","system":"http://terminology.hl7.org/CodeSystem/observation-category"}]}],"code":{"coding":[{"code":"8867-4","display":"Heart rate","system":"http://loinc.org"}]},"derivedFrom":[{"reference":"urn:uuid:69bae1ac-2131-5cb3-951c-b7a03612d430"}],"device":{"reference":"urn:uuid:f25c9573-130f-523c-8aa0-0f06d8dbf989"},"effectivePeriod":{"end":"2026-08-17T15:30:00.256-07:00","start":"2026-08-17T15:30:00.25-07:00"},"extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierElectrocardiogram"},{"url":"https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-method","valueCoding":{"code":"manual-entry","display":"Manual entry","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-recording-method"}},{"url":"http://hl7.org/fhir/StructureDefinition/observation-gatewayDevice","valueReference":{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}},{"url":"http://hl7.org/fhir/StructureDefinition/workflow-researchStudy","valueReference":{"reference":"urn:uuid:38bde736-9a38-596d-82f1-f3e0517c608d","type":"ResearchStudy"}}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:BoF9u897SMv64Ln9nWgrLmX8VA9uyPRdmNk6SJY0krI"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w"}],"meta":{"profile":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-average-heart-rate-observation"]},"resourceType":"Observation","status":"final","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"valueQuantity":{"code":"/min","system":"http://unitsofmeasure.org","unit":"beats/minute","value":72}}],"warnings":[]}]}} +{"id":"electrocardiogram/precedence/zone-before-count","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKMetadataKeyAppleECGAlgorithmVersion":{"integer":2},"HKTimeZone":{"string":"Not/A-Time-Zone"}},"record":{"electrocardiogram":{"reading":{"averageHeartRate":72,"classification":1,"reportedCount":3,"samplingFrequency":500,"symptoms":[],"symptomsStatus":1,"voltages":[{"millivolts":0.125,"offset":0.25},{"millivolts":0.25,"offset":0.252},{"millivolts":-0.125,"offset":0.254},{"millivolts":0,"offset":0.256}]}}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.unsupported-source-value","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.electrocardiogram, GroveHealthKitFHIR.HealthKitValueFailure.unsupportedMetadataValue(GroveHealthKitFHIR.HealthKitMetadataField.timeZone))","location":"HKSample.metadata[HKTimeZone]"}}} +{"id":"electrocardiogram/sample-entry","input":{"convert":{"source":{"context":"plain","end":1787005830,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"bare":{"sampleClass":"HKElectrocardiogram","type":"HKDataTypeIdentifierElectrocardiogram"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.ecg-evidence","error":"ecgEvidence(GroveHealthKitFHIR.HealthKitECGEvidenceFailure.evidenceRequired)","location":"HKElectrocardiogram"}}} +{"id":"heartbeat-series/row","input":{"convert":{"source":{"context":"plain","end":1787005802,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"heartbeatSeries":{"beats":[{"gap":false,"offset":0},{"gap":false,"offset":0.84},{"gap":true,"offset":1.71}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"text/csv","data":"dGltZXN0YW1wLHByZWNlZGVkQnlHYXAKMTc4NzAwNTgwMCwwCjE3ODcwMDU4MDAuODQsMAoxNzg3MDA1ODAxLjcxLDEK","hash":"PznINcuYWCKX6a0UnspSBwERECs=","size":69,"title":"Heartbeat series beat intervals"},"format":{"code":"beat-interval-series","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierHeartbeatSeries"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:iX--MzI0MGrvyapHnU73sSiP2C1nLB-KvIvZjrB-afY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MzKITWeje_hGgybDCN8aIdK4mrEiMwsNqEpreiY1qqw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:EXgECvaw4yJ81Lg6Vw_zCLiEPcJtNX9URuDItFw_J8A"}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-recording-document","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-recording-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"beat-interval-series","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}]}}],"warnings":[]}]}} +{"id":"heartbeat-series/empty","input":{"convert":{"source":{"context":"plain","end":1787005802,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"heartbeatSeries":{"beats":[]}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.empty-recording-series","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.heartbeatSeries, GroveHealthKitFHIR.HealthKitValueFailure.emptyRecordingSeries)","location":"HKSample"}}} +{"id":"heartbeat-series/single","input":{"convert":{"source":{"context":"plain","end":1787005802,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"heartbeatSeries":{"beats":[{"gap":false,"offset":0}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"text/csv","data":"dGltZXN0YW1wLHByZWNlZGVkQnlHYXAKMTc4NzAwNTgwMCwwCg==","hash":"ZKjPnjUDf87xiD49GoYZkPpeWxI=","size":37,"title":"Heartbeat series beat intervals"},"format":{"code":"beat-interval-series","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierHeartbeatSeries"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:iX--MzI0MGrvyapHnU73sSiP2C1nLB-KvIvZjrB-afY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MzKITWeje_hGgybDCN8aIdK4mrEiMwsNqEpreiY1qqw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:EXgECvaw4yJ81Lg6Vw_zCLiEPcJtNX9URuDItFw_J8A"}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-recording-document","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-recording-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"beat-interval-series","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}]}}],"warnings":[]}]}} +{"id":"heartbeat-series/fractional","input":{"convert":{"source":{"context":"plain","end":1787005802,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"heartbeatSeries":{"beats":[{"gap":false,"offset":0.30000000000000004},{"gap":true,"offset":1e-07}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"text/csv","data":"dGltZXN0YW1wLHByZWNlZGVkQnlHYXAKMTc4NzAwNTgwMC4zLDAKMTc4NzAwNTgwMCwxCg==","hash":"/ql3cAb8I1jzrZaqlUgSpaIeHcI=","size":52,"title":"Heartbeat series beat intervals"},"format":{"code":"beat-interval-series","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierHeartbeatSeries"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:iX--MzI0MGrvyapHnU73sSiP2C1nLB-KvIvZjrB-afY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MzKITWeje_hGgybDCN8aIdK4mrEiMwsNqEpreiY1qqw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:EXgECvaw4yJ81Lg6Vw_zCLiEPcJtNX9URuDItFw_J8A"}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-recording-document","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-recording-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"beat-interval-series","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}]}}],"warnings":[]}]}} +{"id":"heartbeat-series/late","input":{"convert":{"source":{"context":"plain","end":1787005802,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"heartbeatSeries":{"beats":[{"gap":false,"offset":86400.5}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"text/csv","data":"dGltZXN0YW1wLHByZWNlZGVkQnlHYXAKMTc4NzA5MjIwMC41LDAK","hash":"fUDLXTA+YRlG3zyZxbjc/rxcyL8=","size":39,"title":"Heartbeat series beat intervals"},"format":{"code":"beat-interval-series","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierHeartbeatSeries"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:iX--MzI0MGrvyapHnU73sSiP2C1nLB-KvIvZjrB-afY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MzKITWeje_hGgybDCN8aIdK4mrEiMwsNqEpreiY1qqw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:EXgECvaw4yJ81Lg6Vw_zCLiEPcJtNX9URuDItFw_J8A"}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-recording-document","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-recording-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"beat-interval-series","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}]}}],"warnings":[]}]}} +{"id":"heartbeat-series/zone-invalid","input":{"convert":{"source":{"context":"plain","end":1787005802,"metadata":{"HKTimeZone":{"string":"Not/A-Time-Zone"}},"record":{"heartbeatSeries":{"beats":[{"gap":false,"offset":0},{"gap":false,"offset":0.84},{"gap":true,"offset":1.71}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"text/csv","data":"dGltZXN0YW1wLHByZWNlZGVkQnlHYXAKMTc4NzAwNTgwMCwwCjE3ODcwMDU4MDAuODQsMAoxNzg3MDA1ODAxLjcxLDEK","hash":"PznINcuYWCKX6a0UnspSBwERECs=","size":69,"title":"Heartbeat series beat intervals"},"format":{"code":"beat-interval-series","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierHeartbeatSeries"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:iX--MzI0MGrvyapHnU73sSiP2C1nLB-KvIvZjrB-afY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MzKITWeje_hGgybDCN8aIdK4mrEiMwsNqEpreiY1qqw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:EXgECvaw4yJ81Lg6Vw_zCLiEPcJtNX9URuDItFw_J8A"}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-recording-document","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-recording-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"beat-interval-series","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}]}}],"warnings":[]}]}} +{"id":"heartbeat-series/linked","input":{"convert":{"source":{"context":"linked","device":"watch","end":1787005802,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"heartbeatSeries":{"beats":[{"gap":false,"offset":0},{"gap":false,"offset":0.84},{"gap":true,"offset":1.71}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:f25c9573-130f-523c-8aa0-0f06d8dbf989"},{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"text/csv","data":"dGltZXN0YW1wLHByZWNlZGVkQnlHYXAKMTc4NzAwNTgwMCwwCjE3ODcwMDU4MDAuODQsMAoxNzg3MDA1ODAxLjcxLDEK","hash":"PznINcuYWCKX6a0UnspSBwERECs=","size":69,"title":"Heartbeat series beat intervals"},"format":{"code":"beat-interval-series","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"context":{"related":[{"reference":"urn:uuid:38bde736-9a38-596d-82f1-f3e0517c608d","type":"ResearchStudy"}]},"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDataTypeIdentifierHeartbeatSeries"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:iX--MzI0MGrvyapHnU73sSiP2C1nLB-KvIvZjrB-afY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MzKITWeje_hGgybDCN8aIdK4mrEiMwsNqEpreiY1qqw"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:EXgECvaw4yJ81Lg6Vw_zCLiEPcJtNX9URuDItFw_J8A"}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-recording-document","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-recording-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"beat-interval-series","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}]}}],"warnings":[]}]}} +{"id":"heartbeat-series/sample-entry","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"bare":{"sampleClass":"HKHeartbeatSeriesSample","type":"HKDataTypeIdentifierHeartbeatSeries"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.platform-exclusive-source-type","error":"platformExclusiveSourceType(GroveHealthKitFHIR.HealthKitSourceType.heartbeatSeries)","location":"HKSample.sampleType"}}} +{"id":"workout-route/row","input":{"convert":{"source":{"context":"plain","end":1787005801,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workoutRoute":{"disclosed":true,"locations":[{"altitude":30.5,"course":91.5,"courseAccuracy":10,"horizontalAccuracy":5,"latitude":37.4275,"longitude":-122.1697,"offset":0,"speed":2.25,"speedAccuracy":0.5,"verticalAccuracy":3},{"altitude":0,"course":-1,"courseAccuracy":-1,"horizontalAccuracy":65,"latitude":37.4276,"longitude":-122.1698,"offset":1,"speed":-1,"speedAccuracy":-1,"verticalAccuracy":-1}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"text/csv","data":"dGltZXN0YW1wLGxhdGl0dWRlLGxvbmdpdHVkZSxhbHRpdHVkZSxob3Jpem9udGFsQWNjdXJhY3ksdmVydGljYWxBY2N1cmFjeSxzcGVlZCxzcGVlZEFjY3VyYWN5LGNvdXJzZSxjb3Vyc2VBY2N1cmFjeQoxNzg3MDA1ODAwLDM3LjQyNzUsLTEyMi4xNjk3LDMwLjUsNSwzLDIuMjUsMC41LDkxLjUsMTAKMTc4NzAwNTgwMSwzNy40Mjc2LC0xMjIuMTY5OCwwLDY1LCwsLCwK","hash":"LGXyPSpUR5Ja3QMX1pYAf72h4mY=","size":210,"title":"Workout route locations"},"format":{"code":"location-track-samples","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutRouteTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:JMuCl2875_WIVVWVhUdUmXKpHZiUYq-WrQOf5mysjDY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:w6au7i2r0efFrZdV-FsTqWrjKXcwLHBpB2EKIa6j2Z8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MMPnrr6rQFLDirazlkUpsFFoe_FPzEcPF5A2ZWwT7bo"}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-recording-document","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-recording-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"location-track-samples","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}]}}],"warnings":[]}]}} +{"id":"workout-route/omitted","input":{"convert":{"source":{"context":"plain","end":1787005801,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workoutRoute":{"disclosed":false,"locations":[{"altitude":30.5,"course":91.5,"courseAccuracy":10,"horizontalAccuracy":5,"latitude":37.4275,"longitude":-122.1697,"offset":0,"speed":2.25,"speedAccuracy":0.5,"verticalAccuracy":3},{"altitude":0,"course":-1,"courseAccuracy":-1,"horizontalAccuracy":65,"latitude":37.4276,"longitude":-122.1698,"offset":1,"speed":-1,"speedAccuracy":-1,"verticalAccuracy":-1}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"omitted":true}} +{"id":"workout-route/empty","input":{"convert":{"source":{"context":"plain","end":1787005801,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workoutRoute":{"disclosed":true,"locations":[]}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.empty-recording-series","error":"invalidValue(GroveHealthKitFHIR.HealthKitSourceType.workoutRoute, GroveHealthKitFHIR.HealthKitValueFailure.emptyRecordingSeries)","location":"HKSample"}}} +{"id":"workout-route/unavailable-readings","input":{"convert":{"source":{"context":"plain","end":1787005801,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workoutRoute":{"disclosed":true,"locations":[{"altitude":30.5,"course":-1,"courseAccuracy":-1,"horizontalAccuracy":5,"latitude":37.4275,"longitude":-122.1697,"offset":0,"speed":-1,"speedAccuracy":-1,"verticalAccuracy":-1},{"altitude":0,"course":-1,"courseAccuracy":-1,"horizontalAccuracy":65,"latitude":37.4276,"longitude":-122.1698,"offset":1,"speed":-1,"speedAccuracy":-1,"verticalAccuracy":-1}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"text/csv","data":"dGltZXN0YW1wLGxhdGl0dWRlLGxvbmdpdHVkZSxhbHRpdHVkZSxob3Jpem9udGFsQWNjdXJhY3ksdmVydGljYWxBY2N1cmFjeSxzcGVlZCxzcGVlZEFjY3VyYWN5LGNvdXJzZSxjb3Vyc2VBY2N1cmFjeQoxNzg3MDA1ODAwLDM3LjQyNzUsLTEyMi4xNjk3LDMwLjUsNSwsLCwsCjE3ODcwMDU4MDEsMzcuNDI3NiwtMTIyLjE2OTgsMCw2NSwsLCwsCg==","hash":"N+1RYZ+9YAyCSOQcnzvOpNJ9q+4=","size":196,"title":"Workout route locations"},"format":{"code":"location-track-samples","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutRouteTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:JMuCl2875_WIVVWVhUdUmXKpHZiUYq-WrQOf5mysjDY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:w6au7i2r0efFrZdV-FsTqWrjKXcwLHBpB2EKIa6j2Z8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MMPnrr6rQFLDirazlkUpsFFoe_FPzEcPF5A2ZWwT7bo"}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-recording-document","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-recording-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"location-track-samples","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}]}}],"warnings":[]}]}} +{"id":"workout-route/linked","input":{"convert":{"source":{"context":"linked","device":"watch","end":1787005801,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"workoutRoute":{"disclosed":true,"locations":[{"altitude":30.5,"course":91.5,"courseAccuracy":10,"horizontalAccuracy":5,"latitude":37.4275,"longitude":-122.1697,"offset":0,"speed":2.25,"speedAccuracy":0.5,"verticalAccuracy":3},{"altitude":0,"course":-1,"courseAccuracy":-1,"horizontalAccuracy":65,"latitude":37.4276,"longitude":-122.1698,"offset":1,"speed":-1,"speedAccuracy":-1,"verticalAccuracy":-1}]}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:f25c9573-130f-523c-8aa0-0f06d8dbf989"},{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"text/csv","data":"dGltZXN0YW1wLGxhdGl0dWRlLGxvbmdpdHVkZSxhbHRpdHVkZSxob3Jpem9udGFsQWNjdXJhY3ksdmVydGljYWxBY2N1cmFjeSxzcGVlZCxzcGVlZEFjY3VyYWN5LGNvdXJzZSxjb3Vyc2VBY2N1cmFjeQoxNzg3MDA1ODAwLDM3LjQyNzUsLTEyMi4xNjk3LDMwLjUsNSwzLDIuMjUsMC41LDkxLjUsMTAKMTc4NzAwNTgwMSwzNy40Mjc2LC0xMjIuMTY5OCwwLDY1LCwsLCwK","hash":"LGXyPSpUR5Ja3QMX1pYAf72h4mY=","size":210,"title":"Workout route locations"},"format":{"code":"location-track-samples","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"context":{"related":[{"reference":"urn:uuid:38bde736-9a38-596d-82f1-f3e0517c608d","type":"ResearchStudy"}]},"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKWorkoutRouteTypeIdentifier"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:JMuCl2875_WIVVWVhUdUmXKpHZiUYq-WrQOf5mysjDY"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:w6au7i2r0efFrZdV-FsTqWrjKXcwLHBpB2EKIa6j2Z8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:MMPnrr6rQFLDirazlkUpsFFoe_FPzEcPF5A2ZWwT7bo"}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-recording-document","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-recording-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"location-track-samples","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}]}}],"warnings":[]}]}} +{"id":"workout-route/sample-entry","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"bare":{"sampleClass":"HKWorkoutRoute","type":"HKWorkoutRouteTypeIdentifier"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.platform-exclusive-source-type","error":"platformExclusiveSourceType(GroveHealthKitFHIR.HealthKitSourceType.workoutRoute)","location":"HKSample.sampleType"}}} +{"id":"cda/row","input":{"convert":{"source":{"context":"plain","end":1787005801,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"cdaDocument":{"document":"\n\n \n \n \n Grove Golden Summary\n \n \n \n ExampleParticipant\n \n Example Hospital\n
NotesExample.
\n
","title":"Grove Golden Summary"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"application/hl7-cda+xml","data":"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPENsaW5pY2FsRG9jdW1lbnQgeG1sbnM9InVybjpobDctb3JnOnYzIj4KICA8dHlwZUlkIHJvb3Q9IjIuMTYuODQwLjEuMTEzODgzLjEuMyIgZXh0ZW5zaW9uPSJQT0NEX0hEMDAwMDQwIi8+CiAgPGlkIHJvb3Q9IjIuMTYuODQwLjEuMTEzODgzLjE5LjUiIGV4dGVuc2lvbj0iZ3JvdmUtZ29sZGVuLTEiLz4KICA8Y29kZSBjb2RlPSIzNDEzMy05IiBjb2RlU3lzdGVtPSIyLjE2Ljg0MC4xLjExMzg4My42LjEiIGRpc3BsYXlOYW1lPSJTdW1tYXJpemF0aW9uIG9mIEVwaXNvZGUgTm90ZSIvPgogIDx0aXRsZT5Hcm92ZSBHb2xkZW4gU3VtbWFyeTwvdGl0bGU+CiAgPGVmZmVjdGl2ZVRpbWUgdmFsdWU9IjIwMjYwODE3MTUzMDAwIi8+CiAgPGNvbmZpZGVudGlhbGl0eUNvZGUgY29kZT0iTiIgY29kZVN5c3RlbT0iMi4xNi44NDAuMS4xMTM4ODMuNS4yNSIvPgogIDxsYW5ndWFnZUNvZGUgY29kZT0iZW4tVVMiLz4KICA8cmVjb3JkVGFyZ2V0PjxwYXRpZW50Um9sZT48aWQgcm9vdD0iMi4xNi44NDAuMS4xMTM4ODMuMTkuNSIgZXh0ZW5zaW9uPSJwLTEiLz48cGF0aWVudD48bmFtZT48Z2l2ZW4+RXhhbXBsZTwvZ2l2ZW4+PGZhbWlseT5QYXJ0aWNpcGFudDwvZmFtaWx5PjwvbmFtZT48L3BhdGllbnQ+PC9wYXRpZW50Um9sZT48L3JlY29yZFRhcmdldD4KICA8YXV0aG9yPjx0aW1lIHZhbHVlPSIyMDI2MDgxNzE1MzAwMCIvPjxhc3NpZ25lZEF1dGhvcj48aWQgcm9vdD0iMi4xNi44NDAuMS4xMTM4ODMuMTkuNSIgZXh0ZW5zaW9uPSJhLTEiLz48YXNzaWduZWRQZXJzb24+PG5hbWU+PGdpdmVuPkFkYTwvZ2l2ZW4+PGZhbWlseT5DbGluaWNpYW48L2ZhbWlseT48L25hbWU+PC9hc3NpZ25lZFBlcnNvbj48L2Fzc2lnbmVkQXV0aG9yPjwvYXV0aG9yPgogIDxjdXN0b2RpYW4+PGFzc2lnbmVkQ3VzdG9kaWFuPjxyZXByZXNlbnRlZEN1c3RvZGlhbk9yZ2FuaXphdGlvbj48aWQgcm9vdD0iMi4xNi44NDAuMS4xMTM4ODMuMTkuNSIgZXh0ZW5zaW9uPSJjLTEiLz48bmFtZT5FeGFtcGxlIEhvc3BpdGFsPC9uYW1lPjwvcmVwcmVzZW50ZWRDdXN0b2RpYW5Pcmdhbml6YXRpb24+PC9hc3NpZ25lZEN1c3RvZGlhbj48L2N1c3RvZGlhbj4KICA8Y29tcG9uZW50PjxzdHJ1Y3R1cmVkQm9keT48Y29tcG9uZW50PjxzZWN0aW9uPjx0aXRsZT5Ob3RlczwvdGl0bGU+PHRleHQ+RXhhbXBsZS48L3RleHQ+PC9zZWN0aW9uPjwvY29tcG9uZW50Pjwvc3RydWN0dXJlZEJvZHk+PC9jb21wb25lbnQ+CjwvQ2xpbmljYWxEb2N1bWVudD4=","hash":"heouxbdCsp2l+KJ9RX8I/BSh+Vg=","size":1289,"title":"Grove Golden Summary"},"format":{"code":"clinical-document","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDocumentTypeIdentifierCDA"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wxV8CBffrQ4U5TmNx87g76N15CGm7mA2-ouIAuUvKho"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Mt87Iz_ixm8Lew0na7d9TZkf7lLvMNE1XvOl5GTppxU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zHXhrQv29KaJ3h73Lqp_ZOpTZhawwF6ijuf6OaNRWSA"}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-recording-document","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-recording-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"clinical-document","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}]}}],"warnings":[]}]}} +{"id":"cda/blank-title","input":{"convert":{"source":{"context":"plain","end":1787005801,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"cdaDocument":{"document":"\n\n \n \n \n Grove Golden Summary\n \n \n \n ExampleParticipant\n \n Example Hospital\n
NotesExample.
\n
","title":" "}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"application/hl7-cda+xml","data":"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPENsaW5pY2FsRG9jdW1lbnQgeG1sbnM9InVybjpobDctb3JnOnYzIj4KICA8dHlwZUlkIHJvb3Q9IjIuMTYuODQwLjEuMTEzODgzLjEuMyIgZXh0ZW5zaW9uPSJQT0NEX0hEMDAwMDQwIi8+CiAgPGlkIHJvb3Q9IjIuMTYuODQwLjEuMTEzODgzLjE5LjUiIGV4dGVuc2lvbj0iZ3JvdmUtZ29sZGVuLTEiLz4KICA8Y29kZSBjb2RlPSIzNDEzMy05IiBjb2RlU3lzdGVtPSIyLjE2Ljg0MC4xLjExMzg4My42LjEiIGRpc3BsYXlOYW1lPSJTdW1tYXJpemF0aW9uIG9mIEVwaXNvZGUgTm90ZSIvPgogIDx0aXRsZT5Hcm92ZSBHb2xkZW4gU3VtbWFyeTwvdGl0bGU+CiAgPGVmZmVjdGl2ZVRpbWUgdmFsdWU9IjIwMjYwODE3MTUzMDAwIi8+CiAgPGNvbmZpZGVudGlhbGl0eUNvZGUgY29kZT0iTiIgY29kZVN5c3RlbT0iMi4xNi44NDAuMS4xMTM4ODMuNS4yNSIvPgogIDxsYW5ndWFnZUNvZGUgY29kZT0iZW4tVVMiLz4KICA8cmVjb3JkVGFyZ2V0PjxwYXRpZW50Um9sZT48aWQgcm9vdD0iMi4xNi44NDAuMS4xMTM4ODMuMTkuNSIgZXh0ZW5zaW9uPSJwLTEiLz48cGF0aWVudD48bmFtZT48Z2l2ZW4+RXhhbXBsZTwvZ2l2ZW4+PGZhbWlseT5QYXJ0aWNpcGFudDwvZmFtaWx5PjwvbmFtZT48L3BhdGllbnQ+PC9wYXRpZW50Um9sZT48L3JlY29yZFRhcmdldD4KICA8YXV0aG9yPjx0aW1lIHZhbHVlPSIyMDI2MDgxNzE1MzAwMCIvPjxhc3NpZ25lZEF1dGhvcj48aWQgcm9vdD0iMi4xNi44NDAuMS4xMTM4ODMuMTkuNSIgZXh0ZW5zaW9uPSJhLTEiLz48YXNzaWduZWRQZXJzb24+PG5hbWU+PGdpdmVuPkFkYTwvZ2l2ZW4+PGZhbWlseT5DbGluaWNpYW48L2ZhbWlseT48L25hbWU+PC9hc3NpZ25lZFBlcnNvbj48L2Fzc2lnbmVkQXV0aG9yPjwvYXV0aG9yPgogIDxjdXN0b2RpYW4+PGFzc2lnbmVkQ3VzdG9kaWFuPjxyZXByZXNlbnRlZEN1c3RvZGlhbk9yZ2FuaXphdGlvbj48aWQgcm9vdD0iMi4xNi44NDAuMS4xMTM4ODMuMTkuNSIgZXh0ZW5zaW9uPSJjLTEiLz48bmFtZT5FeGFtcGxlIEhvc3BpdGFsPC9uYW1lPjwvcmVwcmVzZW50ZWRDdXN0b2RpYW5Pcmdhbml6YXRpb24+PC9hc3NpZ25lZEN1c3RvZGlhbj48L2N1c3RvZGlhbj4KICA8Y29tcG9uZW50PjxzdHJ1Y3R1cmVkQm9keT48Y29tcG9uZW50PjxzZWN0aW9uPjx0aXRsZT5Ob3RlczwvdGl0bGU+PHRleHQ+RXhhbXBsZS48L3RleHQ+PC9zZWN0aW9uPjwvY29tcG9uZW50Pjwvc3RydWN0dXJlZEJvZHk+PC9jb21wb25lbnQ+CjwvQ2xpbmljYWxEb2N1bWVudD4=","hash":"heouxbdCsp2l+KJ9RX8I/BSh+Vg=","size":1289,"title":"Clinical document"},"format":{"code":"clinical-document","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDocumentTypeIdentifierCDA"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wxV8CBffrQ4U5TmNx87g76N15CGm7mA2-ouIAuUvKho"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Mt87Iz_ixm8Lew0na7d9TZkf7lLvMNE1XvOl5GTppxU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zHXhrQv29KaJ3h73Lqp_ZOpTZhawwF6ijuf6OaNRWSA"}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-recording-document","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-recording-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"clinical-document","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}]}}],"warnings":[]}]}} +{"id":"cda/padded-title","input":{"convert":{"source":{"context":"plain","end":1787005801,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"cdaDocument":{"document":"\n\n \n \n \n Grove Golden Summary\n \n \n \n ExampleParticipant\n \n Example Hospital\n
NotesExample.
\n
","title":" Summary\n"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"application/hl7-cda+xml","data":"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPENsaW5pY2FsRG9jdW1lbnQgeG1sbnM9InVybjpobDctb3JnOnYzIj4KICA8dHlwZUlkIHJvb3Q9IjIuMTYuODQwLjEuMTEzODgzLjEuMyIgZXh0ZW5zaW9uPSJQT0NEX0hEMDAwMDQwIi8+CiAgPGlkIHJvb3Q9IjIuMTYuODQwLjEuMTEzODgzLjE5LjUiIGV4dGVuc2lvbj0iZ3JvdmUtZ29sZGVuLTEiLz4KICA8Y29kZSBjb2RlPSIzNDEzMy05IiBjb2RlU3lzdGVtPSIyLjE2Ljg0MC4xLjExMzg4My42LjEiIGRpc3BsYXlOYW1lPSJTdW1tYXJpemF0aW9uIG9mIEVwaXNvZGUgTm90ZSIvPgogIDx0aXRsZT5Hcm92ZSBHb2xkZW4gU3VtbWFyeTwvdGl0bGU+CiAgPGVmZmVjdGl2ZVRpbWUgdmFsdWU9IjIwMjYwODE3MTUzMDAwIi8+CiAgPGNvbmZpZGVudGlhbGl0eUNvZGUgY29kZT0iTiIgY29kZVN5c3RlbT0iMi4xNi44NDAuMS4xMTM4ODMuNS4yNSIvPgogIDxsYW5ndWFnZUNvZGUgY29kZT0iZW4tVVMiLz4KICA8cmVjb3JkVGFyZ2V0PjxwYXRpZW50Um9sZT48aWQgcm9vdD0iMi4xNi44NDAuMS4xMTM4ODMuMTkuNSIgZXh0ZW5zaW9uPSJwLTEiLz48cGF0aWVudD48bmFtZT48Z2l2ZW4+RXhhbXBsZTwvZ2l2ZW4+PGZhbWlseT5QYXJ0aWNpcGFudDwvZmFtaWx5PjwvbmFtZT48L3BhdGllbnQ+PC9wYXRpZW50Um9sZT48L3JlY29yZFRhcmdldD4KICA8YXV0aG9yPjx0aW1lIHZhbHVlPSIyMDI2MDgxNzE1MzAwMCIvPjxhc3NpZ25lZEF1dGhvcj48aWQgcm9vdD0iMi4xNi44NDAuMS4xMTM4ODMuMTkuNSIgZXh0ZW5zaW9uPSJhLTEiLz48YXNzaWduZWRQZXJzb24+PG5hbWU+PGdpdmVuPkFkYTwvZ2l2ZW4+PGZhbWlseT5DbGluaWNpYW48L2ZhbWlseT48L25hbWU+PC9hc3NpZ25lZFBlcnNvbj48L2Fzc2lnbmVkQXV0aG9yPjwvYXV0aG9yPgogIDxjdXN0b2RpYW4+PGFzc2lnbmVkQ3VzdG9kaWFuPjxyZXByZXNlbnRlZEN1c3RvZGlhbk9yZ2FuaXphdGlvbj48aWQgcm9vdD0iMi4xNi44NDAuMS4xMTM4ODMuMTkuNSIgZXh0ZW5zaW9uPSJjLTEiLz48bmFtZT5FeGFtcGxlIEhvc3BpdGFsPC9uYW1lPjwvcmVwcmVzZW50ZWRDdXN0b2RpYW5Pcmdhbml6YXRpb24+PC9hc3NpZ25lZEN1c3RvZGlhbj48L2N1c3RvZGlhbj4KICA8Y29tcG9uZW50PjxzdHJ1Y3R1cmVkQm9keT48Y29tcG9uZW50PjxzZWN0aW9uPjx0aXRsZT5Ob3RlczwvdGl0bGU+PHRleHQ+RXhhbXBsZS48L3RleHQ+PC9zZWN0aW9uPjwvY29tcG9uZW50Pjwvc3RydWN0dXJlZEJvZHk+PC9jb21wb25lbnQ+CjwvQ2xpbmljYWxEb2N1bWVudD4=","hash":"heouxbdCsp2l+KJ9RX8I/BSh+Vg=","size":1289,"title":"Summary"},"format":{"code":"clinical-document","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDocumentTypeIdentifierCDA"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wxV8CBffrQ4U5TmNx87g76N15CGm7mA2-ouIAuUvKho"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Mt87Iz_ixm8Lew0na7d9TZkf7lLvMNE1XvOl5GTppxU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zHXhrQv29KaJ3h73Lqp_ZOpTZhawwF6ijuf6OaNRWSA"}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-recording-document","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-recording-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"clinical-document","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}]}}],"warnings":[]}]}} +{"id":"cda/empty-document","input":{"convert":{"source":{"context":"plain","end":1787005801,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"cdaDocument":{"document":"","title":"Grove Golden Summary"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.clinical-record-empty","error":"clinicalRecord(GroveHealthKitFHIR.HealthKitClinicalRecordFailure.empty)","location":"HKClinicalRecord.fhirResource"}}} +{"id":"cda/no-document","input":{"convert":{"source":{"context":"plain","end":1787005801,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"cdaDocument":{"title":"Grove Golden Summary"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.clinical-record-empty","error":"clinicalRecord(GroveHealthKitFHIR.HealthKitClinicalRecordFailure.empty)","location":"HKClinicalRecord.fhirResource"}}} +{"id":"cda/linked","input":{"convert":{"source":{"context":"linked","device":"watch","end":1787005801,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"},"HKWasUserEntered":{"boolean":true}},"record":{"cdaDocument":{"document":"\n\n \n \n \n Grove Golden Summary\n \n \n \n ExampleParticipant\n \n Example Hospital\n
NotesExample.
\n
","title":"Grove Golden Summary"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:f25c9573-130f-523c-8aa0-0f06d8dbf989"},{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"application/hl7-cda+xml","data":"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPENsaW5pY2FsRG9jdW1lbnQgeG1sbnM9InVybjpobDctb3JnOnYzIj4KICA8dHlwZUlkIHJvb3Q9IjIuMTYuODQwLjEuMTEzODgzLjEuMyIgZXh0ZW5zaW9uPSJQT0NEX0hEMDAwMDQwIi8+CiAgPGlkIHJvb3Q9IjIuMTYuODQwLjEuMTEzODgzLjE5LjUiIGV4dGVuc2lvbj0iZ3JvdmUtZ29sZGVuLTEiLz4KICA8Y29kZSBjb2RlPSIzNDEzMy05IiBjb2RlU3lzdGVtPSIyLjE2Ljg0MC4xLjExMzg4My42LjEiIGRpc3BsYXlOYW1lPSJTdW1tYXJpemF0aW9uIG9mIEVwaXNvZGUgTm90ZSIvPgogIDx0aXRsZT5Hcm92ZSBHb2xkZW4gU3VtbWFyeTwvdGl0bGU+CiAgPGVmZmVjdGl2ZVRpbWUgdmFsdWU9IjIwMjYwODE3MTUzMDAwIi8+CiAgPGNvbmZpZGVudGlhbGl0eUNvZGUgY29kZT0iTiIgY29kZVN5c3RlbT0iMi4xNi44NDAuMS4xMTM4ODMuNS4yNSIvPgogIDxsYW5ndWFnZUNvZGUgY29kZT0iZW4tVVMiLz4KICA8cmVjb3JkVGFyZ2V0PjxwYXRpZW50Um9sZT48aWQgcm9vdD0iMi4xNi44NDAuMS4xMTM4ODMuMTkuNSIgZXh0ZW5zaW9uPSJwLTEiLz48cGF0aWVudD48bmFtZT48Z2l2ZW4+RXhhbXBsZTwvZ2l2ZW4+PGZhbWlseT5QYXJ0aWNpcGFudDwvZmFtaWx5PjwvbmFtZT48L3BhdGllbnQ+PC9wYXRpZW50Um9sZT48L3JlY29yZFRhcmdldD4KICA8YXV0aG9yPjx0aW1lIHZhbHVlPSIyMDI2MDgxNzE1MzAwMCIvPjxhc3NpZ25lZEF1dGhvcj48aWQgcm9vdD0iMi4xNi44NDAuMS4xMTM4ODMuMTkuNSIgZXh0ZW5zaW9uPSJhLTEiLz48YXNzaWduZWRQZXJzb24+PG5hbWU+PGdpdmVuPkFkYTwvZ2l2ZW4+PGZhbWlseT5DbGluaWNpYW48L2ZhbWlseT48L25hbWU+PC9hc3NpZ25lZFBlcnNvbj48L2Fzc2lnbmVkQXV0aG9yPjwvYXV0aG9yPgogIDxjdXN0b2RpYW4+PGFzc2lnbmVkQ3VzdG9kaWFuPjxyZXByZXNlbnRlZEN1c3RvZGlhbk9yZ2FuaXphdGlvbj48aWQgcm9vdD0iMi4xNi44NDAuMS4xMTM4ODMuMTkuNSIgZXh0ZW5zaW9uPSJjLTEiLz48bmFtZT5FeGFtcGxlIEhvc3BpdGFsPC9uYW1lPjwvcmVwcmVzZW50ZWRDdXN0b2RpYW5Pcmdhbml6YXRpb24+PC9hc3NpZ25lZEN1c3RvZGlhbj48L2N1c3RvZGlhbj4KICA8Y29tcG9uZW50PjxzdHJ1Y3R1cmVkQm9keT48Y29tcG9uZW50PjxzZWN0aW9uPjx0aXRsZT5Ob3RlczwvdGl0bGU+PHRleHQ+RXhhbXBsZS48L3RleHQ+PC9zZWN0aW9uPjwvY29tcG9uZW50Pjwvc3RydWN0dXJlZEJvZHk+PC9jb21wb25lbnQ+CjwvQ2xpbmljYWxEb2N1bWVudD4=","hash":"heouxbdCsp2l+KJ9RX8I/BSh+Vg=","size":1289,"title":"Grove Golden Summary"},"format":{"code":"clinical-document","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"context":{"related":[{"reference":"urn:uuid:38bde736-9a38-596d-82f1-f3e0517c608d","type":"ResearchStudy"}]},"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKDocumentTypeIdentifierCDA"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:wxV8CBffrQ4U5TmNx87g76N15CGm7mA2-ouIAuUvKho"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Mt87Iz_ixm8Lew0na7d9TZkf7lLvMNE1XvOl5GTppxU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:zHXhrQv29KaJ3h73Lqp_ZOpTZhawwF6ijuf6OaNRWSA"}],"meta":{"profile":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-recording-document","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-recording-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"clinical-document","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}]}}],"warnings":[]}]}} +{"id":"clinical/type/HKClinicalTypeIdentifierAllergyRecord","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"clinicalRecord":{"fhirVersion":"4.0.1","resource":"{\"resourceType\":\"Observation\",\"id\":\"r4\"}","type":"HKClinicalTypeIdentifierAllergyRecord"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"application/fhir+json; fhirVersion=4.0","data":"eyJyZXNvdXJjZVR5cGUiOiJPYnNlcnZhdGlvbiIsImlkIjoicjQifQ==","hash":"DBo3x1DLNceZatsohPQSJCnJrYA=","size":40,"title":"Allergy Record"},"format":{"code":"fhir-resource","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKClinicalTypeIdentifierAllergyRecord"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:REsDu4g49i0LW02tR0EjKecK48BnNriFCjHnqM1Qlgc"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:t3WtTMZU3oV6vfs0lC1RA6ErB_s3-5nXbn55jugKh_w"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_BPLD_TwcqaMKceRjxFXZGuaAIRNOi6wHWsCUFeQ53M"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-clinical-record-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"allergy-record","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-clinical-record-type"}]}}],"warnings":[]}]}} +{"id":"clinical/type/HKClinicalTypeIdentifierClinicalNoteRecord","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"clinicalRecord":{"fhirVersion":"4.0.1","resource":"{\"resourceType\":\"Observation\",\"id\":\"r4\"}","type":"HKClinicalTypeIdentifierClinicalNoteRecord"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"application/fhir+json; fhirVersion=4.0","data":"eyJyZXNvdXJjZVR5cGUiOiJPYnNlcnZhdGlvbiIsImlkIjoicjQifQ==","hash":"DBo3x1DLNceZatsohPQSJCnJrYA=","size":40,"title":"Clinical Note Record"},"format":{"code":"fhir-resource","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKClinicalTypeIdentifierClinicalNoteRecord"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:9YHH-ekbdoOXt97lJQskyiiq3hNBSed0wQQyu6Rpcws"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:WAmwMpJ7MhkLUTHFfktf-3JUw6ofj-KGvxRQgJfYrcM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:UIk956-2DI8t-7_lCcCUiU9konSjICZYXkpTCXG18_c"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-clinical-record-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"clinical-note-record","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-clinical-record-type"}]}}],"warnings":[]}]}} +{"id":"clinical/type/HKClinicalTypeIdentifierConditionRecord","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"clinicalRecord":{"fhirVersion":"4.0.1","resource":"{\"resourceType\":\"Observation\",\"id\":\"r4\"}","type":"HKClinicalTypeIdentifierConditionRecord"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"application/fhir+json; fhirVersion=4.0","data":"eyJyZXNvdXJjZVR5cGUiOiJPYnNlcnZhdGlvbiIsImlkIjoicjQifQ==","hash":"DBo3x1DLNceZatsohPQSJCnJrYA=","size":40,"title":"Condition Record"},"format":{"code":"fhir-resource","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKClinicalTypeIdentifierConditionRecord"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:KpoQ1s_yswDSNlL3o2rsxl-JQrsFVOhA92Xv5EYufVQ"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:Wd0348zpZIbvvg0bQl1_FEHToKgdj4jGmfCCBEk-O0Y"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:7e5iUVK0ZQ5iHXNXPpfQbhSoXPl1QrYbLgOz7wiqch0"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-clinical-record-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"condition-record","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-clinical-record-type"}]}}],"warnings":[]}]}} +{"id":"clinical/type/HKClinicalTypeIdentifierCoverageRecord","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"clinicalRecord":{"fhirVersion":"4.0.1","resource":"{\"resourceType\":\"Observation\",\"id\":\"r4\"}","type":"HKClinicalTypeIdentifierCoverageRecord"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"application/fhir+json; fhirVersion=4.0","data":"eyJyZXNvdXJjZVR5cGUiOiJPYnNlcnZhdGlvbiIsImlkIjoicjQifQ==","hash":"DBo3x1DLNceZatsohPQSJCnJrYA=","size":40,"title":"Coverage Record"},"format":{"code":"fhir-resource","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKClinicalTypeIdentifierCoverageRecord"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ghyoylCufztNb5v4UsPTmeHl708tobF-DXFlpMgqelg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:lG3PtVtowDGq6_z5UPFrSlIJ9D10Vb_I8gtf8qZDiNg"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:4mSP6Ll2t286Oez7cnKZS_Tgf9th8yM7SHr0uTnV2GY"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-clinical-record-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"coverage-record","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-clinical-record-type"}]}}],"warnings":[]}]}} +{"id":"clinical/type/HKClinicalTypeIdentifierImmunizationRecord","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"clinicalRecord":{"fhirVersion":"4.0.1","resource":"{\"resourceType\":\"Observation\",\"id\":\"r4\"}","type":"HKClinicalTypeIdentifierImmunizationRecord"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"application/fhir+json; fhirVersion=4.0","data":"eyJyZXNvdXJjZVR5cGUiOiJPYnNlcnZhdGlvbiIsImlkIjoicjQifQ==","hash":"DBo3x1DLNceZatsohPQSJCnJrYA=","size":40,"title":"Immunization Record"},"format":{"code":"fhir-resource","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKClinicalTypeIdentifierImmunizationRecord"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:pi-ZU90vzNaJCJUYDLWn0TRj0BMtitCsau_keN7B4c8"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:2QvcrtYxMkj7lH0AbOuQyYzX4wE0OiP895G-CQ624UE"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:u68GsTi_ozeJmGCqYzYrnd3_mBsZEDYtG9frs-CxSWc"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-clinical-record-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"immunization-record","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-clinical-record-type"}]}}],"warnings":[]}]}} +{"id":"clinical/type/HKClinicalTypeIdentifierLabResultRecord","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"clinicalRecord":{"fhirVersion":"4.0.1","resource":"{\"resourceType\":\"Observation\",\"id\":\"r4\"}","type":"HKClinicalTypeIdentifierLabResultRecord"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"application/fhir+json; fhirVersion=4.0","data":"eyJyZXNvdXJjZVR5cGUiOiJPYnNlcnZhdGlvbiIsImlkIjoicjQifQ==","hash":"DBo3x1DLNceZatsohPQSJCnJrYA=","size":40,"title":"Lab Result Record"},"format":{"code":"fhir-resource","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKClinicalTypeIdentifierLabResultRecord"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:k7nQz2zAwnt87fffEE6XdR7l0iy7o6D0_PY0P3X1t7o"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:g75H-jTCTOnctL9sxnLQlyGCDiEwbiUiUbOugvlYJ9M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jEx-lJEn4uAwJvoAkq05jxDm4auQnepg36GCiv4hvCw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-clinical-record-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"lab-result-record","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-clinical-record-type"}]}}],"warnings":[]}]}} +{"id":"clinical/type/HKClinicalTypeIdentifierMedicationRecord","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"clinicalRecord":{"fhirVersion":"4.0.1","resource":"{\"resourceType\":\"Observation\",\"id\":\"r4\"}","type":"HKClinicalTypeIdentifierMedicationRecord"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"application/fhir+json; fhirVersion=4.0","data":"eyJyZXNvdXJjZVR5cGUiOiJPYnNlcnZhdGlvbiIsImlkIjoicjQifQ==","hash":"DBo3x1DLNceZatsohPQSJCnJrYA=","size":40,"title":"Medication Record"},"format":{"code":"fhir-resource","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKClinicalTypeIdentifierMedicationRecord"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:JCdNctfq1enQ29R-43pUuMEX1YgvVWqjZYosBEmbofM"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:3Mk00InYiWVZXfDsXxzw9XFGn_zYCeK8h0ZW9t0Bx0A"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:_rxMiI5Z5SNHsBdlmU5bja4RCglN4WjqO5zIzLCGX9c"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-clinical-record-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"medication-record","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-clinical-record-type"}]}}],"warnings":[]}]}} +{"id":"clinical/type/HKClinicalTypeIdentifierProcedureRecord","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"clinicalRecord":{"fhirVersion":"4.0.1","resource":"{\"resourceType\":\"Observation\",\"id\":\"r4\"}","type":"HKClinicalTypeIdentifierProcedureRecord"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"application/fhir+json; fhirVersion=4.0","data":"eyJyZXNvdXJjZVR5cGUiOiJPYnNlcnZhdGlvbiIsImlkIjoicjQifQ==","hash":"DBo3x1DLNceZatsohPQSJCnJrYA=","size":40,"title":"Procedure Record"},"format":{"code":"fhir-resource","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKClinicalTypeIdentifierProcedureRecord"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:DlDyVSi6Poj8eweUYmr--47feADHuRJ7nNE_AkSmXrU"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:5pl9-sBMciaKZQSAlu-EXCfgjSTNE0vNPupaM0bIj2M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:h0dMdMQGvB527dKhkUWhzn40WA7VNLQPRRWZ79xWLEQ"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-clinical-record-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"procedure-record","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-clinical-record-type"}]}}],"warnings":[]}]}} +{"id":"clinical/type/HKClinicalTypeIdentifierVitalSignRecord","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"clinicalRecord":{"fhirVersion":"4.0.1","resource":"{\"resourceType\":\"Observation\",\"id\":\"r4\"}","type":"HKClinicalTypeIdentifierVitalSignRecord"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"application/fhir+json; fhirVersion=4.0","data":"eyJyZXNvdXJjZVR5cGUiOiJPYnNlcnZhdGlvbiIsImlkIjoicjQifQ==","hash":"DBo3x1DLNceZatsohPQSJCnJrYA=","size":40,"title":"Vital Sign Record"},"format":{"code":"fhir-resource","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKClinicalTypeIdentifierVitalSignRecord"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:S8gBqR2RHltEgsuLmRnqOIgk9fsbD9F8IDYewal3Bok"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:OaEu38CImukYWx2hyYNP0y-rr7RSLlF8ZOuoehDYx1c"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:ZoiMm6rVlXfuXEtAaXNmCo4dRVRQvAsdk8WTtpFFEnY"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-clinical-record-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"vital-sign-record","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-clinical-record-type"}]}}],"warnings":[]}]}} +{"id":"clinical/dstu2","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"clinicalRecord":{"fhirVersion":"1.0.2","resource":"{\"resourceType\":\"Observation\",\"id\":\"dstu2\"}","type":"HKClinicalTypeIdentifierLabResultRecord"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"application/fhir+json; fhirVersion=1.0","data":"eyJyZXNvdXJjZVR5cGUiOiJPYnNlcnZhdGlvbiIsImlkIjoiZHN0dTIifQ==","hash":"k4mJPH3PhCRHDZe2RTKBjLCsCdU=","size":43,"title":"Lab Result Record"},"format":{"code":"fhir-resource","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKClinicalTypeIdentifierLabResultRecord"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:k7nQz2zAwnt87fffEE6XdR7l0iy7o6D0_PY0P3X1t7o"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:g75H-jTCTOnctL9sxnLQlyGCDiEwbiUiUbOugvlYJ9M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jEx-lJEn4uAwJvoAkq05jxDm4auQnepg36GCiv4hvCw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-clinical-record-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"lab-result-record","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-clinical-record-type"}]}}],"warnings":[]}]}} +{"id":"clinical/unknown-release","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"clinicalRecord":{"fhirVersion":"3.0.1","resource":"{\"resourceType\":\"Observation\",\"id\":\"r4\"}","type":"HKClinicalTypeIdentifierLabResultRecord"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.clinical-release-unsupported","error":"clinicalRecord(GroveHealthKitFHIR.HealthKitClinicalRecordFailure.unsupportedRelease)","location":"HKClinicalRecord.fhirResource"}}} +{"id":"clinical/undecodable/duplicate-member","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"clinicalRecord":{"fhirVersion":"4.0.1","resource":"{\"resourceType\":\"Observation\",\"resourceType\":\"Patient\"}","type":"HKClinicalTypeIdentifierLabResultRecord"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"clinicalRecord(GroveHealthKitFHIR.HealthKitClinicalRecordFailure.undecodable)","location":"HKClinicalRecord.fhirResource"}}} +{"id":"clinical/undecodable/lowercase-type","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"clinicalRecord":{"fhirVersion":"4.0.1","resource":"{\"resourceType\":\"observation\"}","type":"HKClinicalTypeIdentifierLabResultRecord"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"clinicalRecord(GroveHealthKitFHIR.HealthKitClinicalRecordFailure.undecodable)","location":"HKClinicalRecord.fhirResource"}}} +{"id":"clinical/undecodable/byte-order-mark","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"clinicalRecord":{"fhirVersion":"4.0.1","resource":"{\"resourceType\":\"Observation\",\"id\":\"r4\"}","type":"HKClinicalTypeIdentifierLabResultRecord"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"clinicalRecord(GroveHealthKitFHIR.HealthKitClinicalRecordFailure.undecodable)","location":"HKClinicalRecord.fhirResource"}}} +{"id":"clinical/undecodable/array","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"clinicalRecord":{"fhirVersion":"4.0.1","resource":"[]","type":"HKClinicalTypeIdentifierLabResultRecord"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"clinicalRecord(GroveHealthKitFHIR.HealthKitClinicalRecordFailure.undecodable)","location":"HKClinicalRecord.fhirResource"}}} +{"id":"clinical/no-resource","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"clinicalRecord":{"fhirVersion":"4.0.1","type":"HKClinicalTypeIdentifierLabResultRecord"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.clinical-record-empty","error":"clinicalRecord(GroveHealthKitFHIR.HealthKitClinicalRecordFailure.empty)","location":"HKClinicalRecord.fhirResource"}}} +{"id":"clinical/whitespace-kept","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"clinicalRecord":{"fhirVersion":"4.0.1","resource":" {\n \"resourceType\": \"Observation\", \"id\": \"r4\"\n}\n","type":"HKClinicalTypeIdentifierLabResultRecord"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"application/fhir+json; fhirVersion=4.0","data":"ICB7CiAgInJlc291cmNlVHlwZSI6ICJPYnNlcnZhdGlvbiIsICJpZCI6ICJyNCIKfQo=","hash":"ZsiNixzNA5EsW7jT8vsqGt4D1K8=","size":50,"title":"Lab Result Record"},"format":{"code":"fhir-resource","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKClinicalTypeIdentifierLabResultRecord"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:k7nQz2zAwnt87fffEE6XdR7l0iy7o6D0_PY0P3X1t7o"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:g75H-jTCTOnctL9sxnLQlyGCDiEwbiUiUbOugvlYJ9M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jEx-lJEn4uAwJvoAkq05jxDm4auQnepg36GCiv4hvCw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-clinical-record-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"lab-result-record","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-clinical-record-type"}]}}],"warnings":[]}]}} +{"id":"clinical/linked","input":{"convert":{"source":{"context":"linked","device":"watch","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"},"HKWasUserEntered":{"boolean":true}},"record":{"clinicalRecord":{"fhirVersion":"4.0.1","resource":"{\"resourceType\":\"Observation\",\"id\":\"r4\"}","type":"HKClinicalTypeIdentifierLabResultRecord"}},"start":1787005800,"writer":"unattributed"}}},"output":{"graphs":[{"outputs":[{"author":[{"reference":"urn:uuid:f25c9573-130f-523c-8aa0-0f06d8dbf989"},{"reference":"urn:uuid:bf4e77bd-bdb5-528c-bb07-79d5cb318fc5"}],"content":[{"attachment":{"contentType":"application/fhir+json; fhirVersion=4.0","data":"eyJyZXNvdXJjZVR5cGUiOiJPYnNlcnZhdGlvbiIsImlkIjoicjQifQ==","hash":"DBo3x1DLNceZatsohPQSJCnJrYA=","size":40,"title":"Lab Result Record"},"format":{"code":"fhir-resource","system":"https://grovealliance.org/fhir/sensor/CodeSystem/grove-recording-format"}}],"context":{"related":[{"reference":"urn:uuid:38bde736-9a38-596d-82f1-f3e0517c608d","type":"ResearchStudy"}]},"date":"2026-08-17T23:30:00Z","extension":[{"url":"https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-source-type","valueCode":"HKClinicalTypeIdentifierLabResultRecord"}],"identifier":[{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-record/test/1","type":{"coding":[{"code":"source-record","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:k7nQz2zAwnt87fffEE6XdR7l0iy7o6D0_PY0P3X1t7o"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-output/test/1","type":{"coding":[{"code":"source-output","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:g75H-jTCTOnctL9sxnLQlyGCDiEwbiUiUbOugvlYJ9M"},{"system":"https://grovealliance.org/fhir/testing/identifiers/healthkit/source-artifact/test/1","type":{"coding":[{"code":"source-artifact","system":"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role"}]},"value":"v0:test:1:jEx-lJEn4uAwJvoAkq05jxDm4auQnepg36GCiv4hvCw"}],"meta":{"profile":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-clinical-record-document"]},"resourceType":"DocumentReference","status":"current","subject":{"identifier":{"system":"https://grovealliance.org/fhir/testing/identifiers/patient","value":"example"},"type":"Patient"},"type":{"coding":[{"code":"lab-result-record","system":"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-clinical-record-type"}]}}],"warnings":[]}]}} +{"id":"clinical/precedence/release-before-payload","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"clinicalRecord":{"fhirVersion":"3.0.1","resource":"{\"resourceType\":\"Observation\",\"resourceType\":\"Patient\"}","type":"HKClinicalTypeIdentifierLabResultRecord"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.clinical-release-unsupported","error":"clinicalRecord(GroveHealthKitFHIR.HealthKitClinicalRecordFailure.unsupportedRelease)","location":"HKClinicalRecord.fhirResource"}}} +{"id":"clinical/precedence/empty-before-release","input":{"convert":{"source":{"context":"plain","end":1787005800,"metadata":{"HKTimeZone":{"string":"America/Los_Angeles"}},"record":{"clinicalRecord":{"fhirVersion":"3.0.1","type":"HKClinicalTypeIdentifierLabResultRecord"}},"start":1787005800,"writer":"unattributed"}}},"output":{"refused":{"code":"healthkit-input.clinical-record-empty","error":"clinicalRecord(GroveHealthKitFHIR.HealthKitClinicalRecordFailure.empty)","location":"HKClinicalRecord.fhirResource"}}} +{"id":"retraction/HKCategoryTypeIdentifierAbdominalCramps","input":{"retract":{"type":"HKCategoryTypeIdentifierAbdominalCramps"}},"output":{"targets":[{"identifier":"v0:test:1:BWUHSvxk1EWbudlHlvSnNhg0dAw6Y-hIqNB9xDPoGxM","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierAcne","input":{"retract":{"type":"HKCategoryTypeIdentifierAcne"}},"output":{"targets":[{"identifier":"v0:test:1:0k83xV0rv4dDOX8SrhbS9JbrDrmkh25Yoxye1HiSWnY","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierAppetiteChanges","input":{"retract":{"type":"HKCategoryTypeIdentifierAppetiteChanges"}},"output":{"targets":[{"identifier":"v0:test:1:ZTkR-x2IMlwUs6ng_QM3qTWucV6FYj2WGD-uSlCsh60","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierAppleStandHour","input":{"retract":{"type":"HKCategoryTypeIdentifierAppleStandHour"}},"output":{"targets":[{"identifier":"v0:test:1:F5qkX0j8T8ydE-WYzM0JQo3lhE2VYMnbV_7xvuovUe4","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierAppleWalkingSteadinessEvent","input":{"retract":{"type":"HKCategoryTypeIdentifierAppleWalkingSteadinessEvent"}},"output":{"targets":[{"identifier":"v0:test:1:s-GMYP48ngVRBRBiW4PlzouY0MUdaLLuGHkeGscQ1y8","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierAudioExposureEvent","input":{"retract":{"type":"HKCategoryTypeIdentifierAudioExposureEvent"}},"output":{"targets":[{"identifier":"v0:test:1:-iCXTqbbBskyri7IcaBCfFLZpRAInufs3lpYL0l-7tA","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierBladderIncontinence","input":{"retract":{"type":"HKCategoryTypeIdentifierBladderIncontinence"}},"output":{"targets":[{"identifier":"v0:test:1:bKe255DsoQeWtXCRRcdGuS-dtR8qlr8ShcRa3FWIcDg","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierBleedingAfterPregnancy","input":{"retract":{"type":"HKCategoryTypeIdentifierBleedingAfterPregnancy"}},"output":{"targets":[{"identifier":"v0:test:1:O0CSe5uH-g35_KP_WE07M3zA0jsz97swtcUoDUeOVT8","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierBleedingDuringPregnancy","input":{"retract":{"type":"HKCategoryTypeIdentifierBleedingDuringPregnancy"}},"output":{"targets":[{"identifier":"v0:test:1:dfqSrJx2S0wyYD3m_mLXDjC38DYrOca6c7npEs3tyt0","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierBloating","input":{"retract":{"type":"HKCategoryTypeIdentifierBloating"}},"output":{"targets":[{"identifier":"v0:test:1:2Ol4dL_K_7arRIP67HZRk0Gr4pipq_CBp9_xonDynqk","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierBreastPain","input":{"retract":{"type":"HKCategoryTypeIdentifierBreastPain"}},"output":{"targets":[{"identifier":"v0:test:1:aCD6ZHuJRMs902PhicWWieMWTp_3wdOIv7XX3NYPDwA","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierCervicalMucusQuality","input":{"retract":{"type":"HKCategoryTypeIdentifierCervicalMucusQuality"}},"output":{"targets":[{"identifier":"v0:test:1:bZbGQvdQDBe_CTKOS3APnVsH-0h00FOIh2YIDCui5X0","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierChestTightnessOrPain","input":{"retract":{"type":"HKCategoryTypeIdentifierChestTightnessOrPain"}},"output":{"targets":[{"identifier":"v0:test:1:Lw3JVv6KA9zpIWgSOLWEwlj2xKGLWsJMcFOHp3d_baQ","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierChills","input":{"retract":{"type":"HKCategoryTypeIdentifierChills"}},"output":{"targets":[{"identifier":"v0:test:1:IKHfap3O-8cwiyFNaAoZHBOkdoYtZdqs0wra8J-LXfk","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierConstipation","input":{"retract":{"type":"HKCategoryTypeIdentifierConstipation"}},"output":{"targets":[{"identifier":"v0:test:1:2lVN-2BrrS32sO63zzua6uTRgZjBUHAXoh0ITCGhYkQ","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierContraceptive","input":{"retract":{"type":"HKCategoryTypeIdentifierContraceptive"}},"output":{"targets":[{"identifier":"v0:test:1:CwF4NQXHkhALu36DUCC9PF6EHARYwBvsjIc0sbP4aBs","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierCoughing","input":{"retract":{"type":"HKCategoryTypeIdentifierCoughing"}},"output":{"targets":[{"identifier":"v0:test:1:qJsHDskS1PWg3gVeify1nBHeceRthS0aKeFvqUA4tlE","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierDiarrhea","input":{"retract":{"type":"HKCategoryTypeIdentifierDiarrhea"}},"output":{"targets":[{"identifier":"v0:test:1:xFqUHL8d7nH6SUYf8KK6fCiStkv0R4tDntgjEAfDSRA","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierDizziness","input":{"retract":{"type":"HKCategoryTypeIdentifierDizziness"}},"output":{"targets":[{"identifier":"v0:test:1:tBw_HTmuXG5cTnYvOK5VUTyk6wNa225-gRa0oSbQOv0","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierDrySkin","input":{"retract":{"type":"HKCategoryTypeIdentifierDrySkin"}},"output":{"targets":[{"identifier":"v0:test:1:BYLsmSKqtJEitGwPeP2Y_fYQkmnOojvRWY2zb8Csfu4","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierFainting","input":{"retract":{"type":"HKCategoryTypeIdentifierFainting"}},"output":{"targets":[{"identifier":"v0:test:1:4XtlWh1vPgYcZlCHrNxvnqkfhVmj0JdR9SB8l-7ro9A","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierFatigue","input":{"retract":{"type":"HKCategoryTypeIdentifierFatigue"}},"output":{"targets":[{"identifier":"v0:test:1:na3PLyGByvdbKWCWY19d2jJ-_gelcemkA8FTk4TqFhU","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierFever","input":{"retract":{"type":"HKCategoryTypeIdentifierFever"}},"output":{"targets":[{"identifier":"v0:test:1:nHNjypoVhSgGaSjuiQCnhbpFekFsOfwd9d4nY6vIqCc","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierGeneralizedBodyAche","input":{"retract":{"type":"HKCategoryTypeIdentifierGeneralizedBodyAche"}},"output":{"targets":[{"identifier":"v0:test:1:AlSQT8pWOMLtyIxktMjkrn6HzLcUaEC5YYbNzGmw9Sk","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierHairLoss","input":{"retract":{"type":"HKCategoryTypeIdentifierHairLoss"}},"output":{"targets":[{"identifier":"v0:test:1:Lh2-3i7ZCF_6R-GueAcwlARdMrT3bMrOuNlgMk6OC7o","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierHandwashingEvent","input":{"retract":{"type":"HKCategoryTypeIdentifierHandwashingEvent"}},"output":{"targets":[{"identifier":"v0:test:1:kxzVpepYqorfwgqCkZya1v8tXMlUzIiVMRy4bEBXqto","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierHeadache","input":{"retract":{"type":"HKCategoryTypeIdentifierHeadache"}},"output":{"targets":[{"identifier":"v0:test:1:WzxAoC5vaWc9qHY5cqOQpSRs4qfD2mUfUTyxdG6lCQs","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierHeadphoneAudioExposureEvent","input":{"retract":{"type":"HKCategoryTypeIdentifierHeadphoneAudioExposureEvent"}},"output":{"targets":[{"identifier":"v0:test:1:M6dtPpDQiQNY97jaOwLyhYjDcxpuUiCADEsPN1NIMRo","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierHeartburn","input":{"retract":{"type":"HKCategoryTypeIdentifierHeartburn"}},"output":{"targets":[{"identifier":"v0:test:1:8kQdzpgbsmSI8db7wIrQbjsUu25_t_xDklIs9BSzewo","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierHighHeartRateEvent","input":{"retract":{"type":"HKCategoryTypeIdentifierHighHeartRateEvent"}},"output":{"targets":[{"identifier":"v0:test:1:flw7kSiSYsr-iveqdkgRbq5iyqK9V-h-NkGfndurIkA","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierHotFlashes","input":{"retract":{"type":"HKCategoryTypeIdentifierHotFlashes"}},"output":{"targets":[{"identifier":"v0:test:1:M5dXio6aQQJyZ_9LpNKuhKeyrZsHsI2r5Z--vz6kydM","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierHypertensionEvent","input":{"retract":{"type":"HKCategoryTypeIdentifierHypertensionEvent"}},"output":{"targets":[{"identifier":"v0:test:1:LF4Uxf1_aMpQs6QIDUV6GWUBaz6wHD1-X6LX1KwWxPc","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierInfrequentMenstrualCycles","input":{"retract":{"type":"HKCategoryTypeIdentifierInfrequentMenstrualCycles"}},"output":{"targets":[{"identifier":"v0:test:1:-euebf521qP-bvYvFd0jubW4b5VDEaElByXNJVlFzv8","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierIntermenstrualBleeding","input":{"retract":{"type":"HKCategoryTypeIdentifierIntermenstrualBleeding"}},"output":{"targets":[{"identifier":"v0:test:1:bKoMTKr4cm3CAvJksNYfNNmujgEBJG3weD_CfPiRVCM","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierIrregularHeartRhythmEvent","input":{"retract":{"type":"HKCategoryTypeIdentifierIrregularHeartRhythmEvent"}},"output":{"targets":[{"identifier":"v0:test:1:8eStXK6ppOUBT4ts3Uxo8KOaau5db3rT98BIoZIN0jg","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierIrregularMenstrualCycles","input":{"retract":{"type":"HKCategoryTypeIdentifierIrregularMenstrualCycles"}},"output":{"targets":[{"identifier":"v0:test:1:moVsYlU6Ec4HrOyMjiRxVQ2tWaiMnjRLgVoY7vsETsU","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierLactation","input":{"retract":{"type":"HKCategoryTypeIdentifierLactation"}},"output":{"targets":[{"identifier":"v0:test:1:lKFyBHCLObWVdiif3JJssZVhGP0Wi4jTk4m2yqZL2Rc","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierLossOfSmell","input":{"retract":{"type":"HKCategoryTypeIdentifierLossOfSmell"}},"output":{"targets":[{"identifier":"v0:test:1:R4UvgtjwlIpKNHNZ7p5soy_K2U7AJsEKbMyvC6Lv7qM","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierLossOfTaste","input":{"retract":{"type":"HKCategoryTypeIdentifierLossOfTaste"}},"output":{"targets":[{"identifier":"v0:test:1:1ZPKgBUXe_UFpNSp0YE5Y7Fr_DHBOK2uWsZ91u-iQDE","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierLowCardioFitnessEvent","input":{"retract":{"type":"HKCategoryTypeIdentifierLowCardioFitnessEvent"}},"output":{"targets":[{"identifier":"v0:test:1:SX4gfMq0PMTuym8xez1diEYN0Lxu7os5rDcTXBY9Ufw","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierLowHeartRateEvent","input":{"retract":{"type":"HKCategoryTypeIdentifierLowHeartRateEvent"}},"output":{"targets":[{"identifier":"v0:test:1:LTPRj6ezDwnTRUXeU_SPpJkyThJ3IT64RH9R5Tq0iOE","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierLowerBackPain","input":{"retract":{"type":"HKCategoryTypeIdentifierLowerBackPain"}},"output":{"targets":[{"identifier":"v0:test:1:jez5mjRQ7elrEfgeFTIj8cVLWoBVl6SpA3giCQuP-Ic","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierMemoryLapse","input":{"retract":{"type":"HKCategoryTypeIdentifierMemoryLapse"}},"output":{"targets":[{"identifier":"v0:test:1:vVy3XzciLkXIq5nm6-tNJ9HcZQXBivg2FIOoDsQBLcI","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierMenstrualFlow","input":{"retract":{"type":"HKCategoryTypeIdentifierMenstrualFlow"}},"output":{"targets":[{"identifier":"v0:test:1:i2VZaK7j7kjlmoihuJaK8_l9eGPvDFPEdHfePQSIu_8","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierMindfulSession","input":{"retract":{"type":"HKCategoryTypeIdentifierMindfulSession"}},"output":{"targets":[{"identifier":"v0:test:1:S8i6GwVGbrJCBfgPnQHMuAoTXERMdUkRw1CoDk1XaMc","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierMoodChanges","input":{"retract":{"type":"HKCategoryTypeIdentifierMoodChanges"}},"output":{"targets":[{"identifier":"v0:test:1:aIqMDecpOwP_FBeQbulkSc9T9Jkrq3k5LJHfSbfo3kI","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierNausea","input":{"retract":{"type":"HKCategoryTypeIdentifierNausea"}},"output":{"targets":[{"identifier":"v0:test:1:g3jwvyODEW0zH-DhOE4PBsPHPe7LT6CQLIjIygLsTpI","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierNightSweats","input":{"retract":{"type":"HKCategoryTypeIdentifierNightSweats"}},"output":{"targets":[{"identifier":"v0:test:1:vfR8UJhGBYHDx4VVA4HKdsLDPD606Fu0TSa34GWy7cg","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierOvulationTestResult","input":{"retract":{"type":"HKCategoryTypeIdentifierOvulationTestResult"}},"output":{"targets":[{"identifier":"v0:test:1:o2pCLBZ7cGa3sQSKUT0OhObihGQQh7uaFf1fdghr9Js","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierPelvicPain","input":{"retract":{"type":"HKCategoryTypeIdentifierPelvicPain"}},"output":{"targets":[{"identifier":"v0:test:1:_TJexnGlS9w-Aj3SwYI5JJ0XbpllcExCAX55YojTkBw","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierPersistentIntermenstrualBleeding","input":{"retract":{"type":"HKCategoryTypeIdentifierPersistentIntermenstrualBleeding"}},"output":{"targets":[{"identifier":"v0:test:1:S-TPyick34TJ0gbuh2lKlGA7DCqfWdoNL4uLfd1Ijp0","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierPregnancy","input":{"retract":{"type":"HKCategoryTypeIdentifierPregnancy"}},"output":{"targets":[{"identifier":"v0:test:1:wop6SpzrLMNc40CAtdA2yCAM9wtC1nu79i1Oiw8AmVw","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierPregnancyTestResult","input":{"retract":{"type":"HKCategoryTypeIdentifierPregnancyTestResult"}},"output":{"targets":[{"identifier":"v0:test:1:vYxjvXi5DUn-eQ-MebFoXAdYLBQE_LKyWwDXv7PJruk","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierProgesteroneTestResult","input":{"retract":{"type":"HKCategoryTypeIdentifierProgesteroneTestResult"}},"output":{"targets":[{"identifier":"v0:test:1:AMqSrapPTfID_6OrmSYl0nmFqAYF2J0mMsZrpGUF5xY","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierProlongedMenstrualPeriods","input":{"retract":{"type":"HKCategoryTypeIdentifierProlongedMenstrualPeriods"}},"output":{"targets":[{"identifier":"v0:test:1:oHFIvU-qnJi5UdOTls1G7w1GqkMl7ScizkKJ8lAM2dw","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat","input":{"retract":{"type":"HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat"}},"output":{"targets":[{"identifier":"v0:test:1:TZv0OK9uHuaqb95K1HJLS_Rq7iio7lIpyjFw1hlazTQ","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierRunnyNose","input":{"retract":{"type":"HKCategoryTypeIdentifierRunnyNose"}},"output":{"targets":[{"identifier":"v0:test:1:MsEGB8I5v7viO6XMQuUcHZzLQ7K7ROKaJ2aU4eAK16Q","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierSexualActivity","input":{"retract":{"type":"HKCategoryTypeIdentifierSexualActivity"}},"output":{"targets":[{"identifier":"v0:test:1:FI4pGDsSw5sWnaPieuPeuqDvYzsl-wNnSQ_onDCux1I","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierShortnessOfBreath","input":{"retract":{"type":"HKCategoryTypeIdentifierShortnessOfBreath"}},"output":{"targets":[{"identifier":"v0:test:1:_1YBOamNGfGxjJQP2uskQ4GwtxUzZG7EPQeEmdZqB3g","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierSinusCongestion","input":{"retract":{"type":"HKCategoryTypeIdentifierSinusCongestion"}},"output":{"targets":[{"identifier":"v0:test:1:USTe5Tfsfg4CzDeKERk6FwFGZhJhV6NsJgmD3aMin6Q","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierSkippedHeartbeat","input":{"retract":{"type":"HKCategoryTypeIdentifierSkippedHeartbeat"}},"output":{"targets":[{"identifier":"v0:test:1:dG58gX13PHrqyvI0kkJgM73PbiUUpNgJvndrZFkraNE","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierSleepAnalysis","input":{"retract":{"type":"HKCategoryTypeIdentifierSleepAnalysis"}},"output":{"targets":[{"identifier":"v0:test:1:sQvdH5bt3Mi-S5ng5AsHsyg3sygBMl_XcztZi4V2STA","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierSleepApneaEvent","input":{"retract":{"type":"HKCategoryTypeIdentifierSleepApneaEvent"}},"output":{"targets":[{"identifier":"v0:test:1:w4avGeqB4nSza-deaqIzncwLu5LMzajWVP3m_uubjbE","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierSleepChanges","input":{"retract":{"type":"HKCategoryTypeIdentifierSleepChanges"}},"output":{"targets":[{"identifier":"v0:test:1:B_A7yKPDpvp_ER8YO6GmG_xvTG4KeWihK35kRqb3XSE","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierSoreThroat","input":{"retract":{"type":"HKCategoryTypeIdentifierSoreThroat"}},"output":{"targets":[{"identifier":"v0:test:1:hdrFcP70I1watCiWm1QT7b_i0NyvaNc6HCNWC5ETEfs","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierToothbrushingEvent","input":{"retract":{"type":"HKCategoryTypeIdentifierToothbrushingEvent"}},"output":{"targets":[{"identifier":"v0:test:1:l9x5fcO4lAHMq4FaVVsGjbJBNEioNnl5h9sCGNCaJPc","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierVaginalDryness","input":{"retract":{"type":"HKCategoryTypeIdentifierVaginalDryness"}},"output":{"targets":[{"identifier":"v0:test:1:yTUVa_gXwzCKhXNyWNydsEdhivTwwTgtScyhTqziwHA","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierVomiting","input":{"retract":{"type":"HKCategoryTypeIdentifierVomiting"}},"output":{"targets":[{"identifier":"v0:test:1:_MnLaPiGY7QV3fKzyxzSLFwQYD-7Ku5q541ip5eG7BM","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCategoryTypeIdentifierWheezing","input":{"retract":{"type":"HKCategoryTypeIdentifierWheezing"}},"output":{"targets":[{"identifier":"v0:test:1:XwlM_8E6938ySrAdqN86k4kVGfIqtTo0nFcZWJ9GXrc","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCharacteristicTypeIdentifierActivityMoveMode","input":{"retract":{"type":"HKCharacteristicTypeIdentifierActivityMoveMode"}},"output":{"refused":{"code":"mobile-input.intentionally-unsupported-source-type","error":"intentionallyUnsupported(GroveHealthKitFHIR.HealthKitSourceType.activityMoveMode, reason: \"A ring-display preference has no semantically exact Mobile meaning, and converting it would encode an Apple product configuration as clinical data. The mode is interpretive context for the Apple move-time and active-energy rows, which carry their own units and are converted in their own right; it adds no measurement content of its own.\")","location":"HKSample.sampleType"}}} +{"id":"retraction/HKCharacteristicTypeIdentifierBiologicalSex","input":{"retract":{"type":"HKCharacteristicTypeIdentifierBiologicalSex"}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"unsupportedSourceType(GroveHealthKitFHIR.HealthKitSourceType.biologicalSex)","location":"HKSample.sampleType"}}} +{"id":"retraction/HKCharacteristicTypeIdentifierBloodType","input":{"retract":{"type":"HKCharacteristicTypeIdentifierBloodType"}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"unsupportedSourceType(GroveHealthKitFHIR.HealthKitSourceType.bloodType)","location":"HKSample.sampleType"}}} +{"id":"retraction/HKCharacteristicTypeIdentifierDateOfBirth","input":{"retract":{"type":"HKCharacteristicTypeIdentifierDateOfBirth"}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"unsupportedSourceType(GroveHealthKitFHIR.HealthKitSourceType.dateOfBirth)","location":"HKSample.sampleType"}}} +{"id":"retraction/HKCharacteristicTypeIdentifierFitzpatrickSkinType","input":{"retract":{"type":"HKCharacteristicTypeIdentifierFitzpatrickSkinType"}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"unsupportedSourceType(GroveHealthKitFHIR.HealthKitSourceType.fitzpatrickSkinType)","location":"HKSample.sampleType"}}} +{"id":"retraction/HKCharacteristicTypeIdentifierWheelchairUse","input":{"retract":{"type":"HKCharacteristicTypeIdentifierWheelchairUse"}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"unsupportedSourceType(GroveHealthKitFHIR.HealthKitSourceType.wheelchairUse)","location":"HKSample.sampleType"}}} +{"id":"retraction/HKClinicalTypeIdentifierAllergyRecord","input":{"retract":{"type":"HKClinicalTypeIdentifierAllergyRecord"}},"output":{"targets":[{"identifier":"v0:test:1:t3WtTMZU3oV6vfs0lC1RA6ErB_s3-5nXbn55jugKh_w","identifierRole":"source-output","resourceType":"DocumentReference","role":"source-artifact"}]}} +{"id":"retraction/HKClinicalTypeIdentifierClinicalNoteRecord","input":{"retract":{"type":"HKClinicalTypeIdentifierClinicalNoteRecord"}},"output":{"targets":[{"identifier":"v0:test:1:WAmwMpJ7MhkLUTHFfktf-3JUw6ofj-KGvxRQgJfYrcM","identifierRole":"source-output","resourceType":"DocumentReference","role":"source-artifact"}]}} +{"id":"retraction/HKClinicalTypeIdentifierConditionRecord","input":{"retract":{"type":"HKClinicalTypeIdentifierConditionRecord"}},"output":{"targets":[{"identifier":"v0:test:1:Wd0348zpZIbvvg0bQl1_FEHToKgdj4jGmfCCBEk-O0Y","identifierRole":"source-output","resourceType":"DocumentReference","role":"source-artifact"}]}} +{"id":"retraction/HKClinicalTypeIdentifierCoverageRecord","input":{"retract":{"type":"HKClinicalTypeIdentifierCoverageRecord"}},"output":{"targets":[{"identifier":"v0:test:1:lG3PtVtowDGq6_z5UPFrSlIJ9D10Vb_I8gtf8qZDiNg","identifierRole":"source-output","resourceType":"DocumentReference","role":"source-artifact"}]}} +{"id":"retraction/HKClinicalTypeIdentifierImmunizationRecord","input":{"retract":{"type":"HKClinicalTypeIdentifierImmunizationRecord"}},"output":{"targets":[{"identifier":"v0:test:1:2QvcrtYxMkj7lH0AbOuQyYzX4wE0OiP895G-CQ624UE","identifierRole":"source-output","resourceType":"DocumentReference","role":"source-artifact"}]}} +{"id":"retraction/HKClinicalTypeIdentifierLabResultRecord","input":{"retract":{"type":"HKClinicalTypeIdentifierLabResultRecord"}},"output":{"targets":[{"identifier":"v0:test:1:g75H-jTCTOnctL9sxnLQlyGCDiEwbiUiUbOugvlYJ9M","identifierRole":"source-output","resourceType":"DocumentReference","role":"source-artifact"}]}} +{"id":"retraction/HKClinicalTypeIdentifierMedicationRecord","input":{"retract":{"type":"HKClinicalTypeIdentifierMedicationRecord"}},"output":{"targets":[{"identifier":"v0:test:1:3Mk00InYiWVZXfDsXxzw9XFGn_zYCeK8h0ZW9t0Bx0A","identifierRole":"source-output","resourceType":"DocumentReference","role":"source-artifact"}]}} +{"id":"retraction/HKClinicalTypeIdentifierProcedureRecord","input":{"retract":{"type":"HKClinicalTypeIdentifierProcedureRecord"}},"output":{"targets":[{"identifier":"v0:test:1:5pl9-sBMciaKZQSAlu-EXCfgjSTNE0vNPupaM0bIj2M","identifierRole":"source-output","resourceType":"DocumentReference","role":"source-artifact"}]}} +{"id":"retraction/HKClinicalTypeIdentifierVitalSignRecord","input":{"retract":{"type":"HKClinicalTypeIdentifierVitalSignRecord"}},"output":{"targets":[{"identifier":"v0:test:1:OaEu38CImukYWx2hyYNP0y-rr7RSLlF8ZOuoehDYx1c","identifierRole":"source-output","resourceType":"DocumentReference","role":"source-artifact"}]}} +{"id":"retraction/HKCorrelationTypeIdentifierBloodPressure","input":{"retract":{"type":"HKCorrelationTypeIdentifierBloodPressure"}},"output":{"targets":[{"identifier":"v0:test:1:wYZqj9o2nHYQ_5L_6eXr6AyxGkXTo2hPBmQu8SUzugY","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKCorrelationTypeIdentifierFood","input":{"retract":{"type":"HKCorrelationTypeIdentifierFood"}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"unsupportedSourceType(GroveHealthKitFHIR.HealthKitSourceType.food)","location":"HKSample.sampleType"}}} +{"id":"retraction/HKDataTypeIdentifierAudiogram","input":{"retract":{"type":"HKDataTypeIdentifierAudiogram"}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"unsupportedSourceType(GroveHealthKitFHIR.HealthKitSourceType.audiogram)","location":"HKSample.sampleType"}}} +{"id":"retraction/HKDataTypeIdentifierElectrocardiogram","input":{"retract":{"type":"HKDataTypeIdentifierElectrocardiogram"}},"output":{"targets":[{"identifier":"v0:test:1:E_FGHzZnZXCiN-tutD53YNDMGJNMX3EqMd7Z7HaLly0","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"},{"identifier":"v0:test:1:v8jl06r_SPRbaCJYKf-khvT4yE5y9zo6Rvqv3gbJ2-w","identifierRole":"source-output","resourceType":"Observation","role":"child-output"}]}} +{"id":"retraction/HKDataTypeIdentifierHeartbeatSeries","input":{"retract":{"type":"HKDataTypeIdentifierHeartbeatSeries"}},"output":{"targets":[{"identifier":"v0:test:1:MzKITWeje_hGgybDCN8aIdK4mrEiMwsNqEpreiY1qqw","identifierRole":"source-output","resourceType":"DocumentReference","role":"source-artifact"}]}} +{"id":"retraction/HKDataTypeStateOfMind","input":{"retract":{"type":"HKDataTypeStateOfMind"}},"output":{"targets":[{"identifier":"v0:test:1:-NWtv71_hvrPTgsE-V6yrdHedmnyt9jG9HNbYeSB25k","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKDataTypeUserAnnotatedMedicationConcept","input":{"retract":{"type":"HKDataTypeUserAnnotatedMedicationConcept"}},"output":{"refused":{"code":"mobile-input.platform-exclusive-source-type","error":"platformExclusiveSourceType(GroveHealthKitFHIR.HealthKitSourceType.userAnnotatedMedicationConcept)","location":"HKSample.sampleType"}}} +{"id":"retraction/HKDocumentTypeIdentifierCDA","input":{"retract":{"type":"HKDocumentTypeIdentifierCDA"}},"output":{"targets":[{"identifier":"v0:test:1:Mt87Iz_ixm8Lew0na7d9TZkf7lLvMNE1XvOl5GTppxU","identifierRole":"source-output","resourceType":"DocumentReference","role":"source-artifact"}]}} +{"id":"retraction/HKMedicationDoseEventTypeIdentifierMedicationDoseEvent","input":{"retract":{"type":"HKMedicationDoseEventTypeIdentifierMedicationDoseEvent"}},"output":{"refused":{"code":"mobile-input.platform-exclusive-source-type","error":"platformExclusiveSourceType(GroveHealthKitFHIR.HealthKitSourceType.medicationDoseEvent)","location":"HKSample.sampleType"}}} +{"id":"retraction/HKQuantityTypeIdentifierActiveEnergyBurned","input":{"retract":{"type":"HKQuantityTypeIdentifierActiveEnergyBurned"}},"output":{"targets":[{"identifier":"v0:test:1:by7cX6De0XCHR0rVxwlhYhH2IsUPbTipqvFbRptDfnI","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierAppleExerciseTime","input":{"retract":{"type":"HKQuantityTypeIdentifierAppleExerciseTime"}},"output":{"targets":[{"identifier":"v0:test:1:0Bwxf9MUhL7_L59w8a6RDVfo2b5F1NL8-yEto4TLzNU","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierAppleMoveTime","input":{"retract":{"type":"HKQuantityTypeIdentifierAppleMoveTime"}},"output":{"targets":[{"identifier":"v0:test:1:4w9PBWp-qmgB7fME366hfY-LddIWG0p731lefRPuY1A","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances","input":{"retract":{"type":"HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances"}},"output":{"targets":[{"identifier":"v0:test:1:PTq104naXZTMLdb2IFhVtdFWnypYy1KwqJjG8jnvIwA","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierAppleSleepingWristTemperature","input":{"retract":{"type":"HKQuantityTypeIdentifierAppleSleepingWristTemperature"}},"output":{"targets":[{"identifier":"v0:test:1:3oToEJ4tdOm0wuEA6632dkhNKCxSVhggXHU6fy1EwSc","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierAppleStandTime","input":{"retract":{"type":"HKQuantityTypeIdentifierAppleStandTime"}},"output":{"targets":[{"identifier":"v0:test:1:daOjL79ce3xQTDRVgROPuo8dN8W_eSLZJ4nHGejd0ew","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierAppleWalkingSteadiness","input":{"retract":{"type":"HKQuantityTypeIdentifierAppleWalkingSteadiness"}},"output":{"targets":[{"identifier":"v0:test:1:PNWdwvoy4bBXmF_lCQrDnEV6yW3CidJRTg5v4L_tPJQ","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierAtrialFibrillationBurden","input":{"retract":{"type":"HKQuantityTypeIdentifierAtrialFibrillationBurden"}},"output":{"targets":[{"identifier":"v0:test:1:WFpyh4vwA1cbaQ4A8WEmRPD7dvo6ZnjXF857GwsiwZQ","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierBasalBodyTemperature","input":{"retract":{"type":"HKQuantityTypeIdentifierBasalBodyTemperature"}},"output":{"targets":[{"identifier":"v0:test:1:COK232J8yTuX4xZPiSZwvVK23RpizedCioxUAf8r-zM","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierBasalEnergyBurned","input":{"retract":{"type":"HKQuantityTypeIdentifierBasalEnergyBurned"}},"output":{"targets":[{"identifier":"v0:test:1:3WJq1-cJKeCOCSnqD0lK8N70nChwgPuw5f-A3Xvxn2s","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierBloodAlcoholContent","input":{"retract":{"type":"HKQuantityTypeIdentifierBloodAlcoholContent"}},"output":{"targets":[{"identifier":"v0:test:1:5tp9BhWRjAxEGuFMm_UyZXEpxakSh46dcqNPE-N4wLI","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierBloodGlucose","input":{"retract":{"type":"HKQuantityTypeIdentifierBloodGlucose"}},"output":{"targets":[{"identifier":"v0:test:1:_yR4sXoau44VkcKMiVWaenSYlvQ0HGr5GT4No7NFvoY","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierBloodPressureDiastolic","input":{"retract":{"type":"HKQuantityTypeIdentifierBloodPressureDiastolic"}},"output":{"refused":{"code":"healthkit-input.component-requires-correlation","error":"componentRequiresCorrelation(GroveHealthKitFHIR.HealthKitSourceType.bloodPressureDiastolic)","location":"HKSample.sampleType"}}} +{"id":"retraction/HKQuantityTypeIdentifierBloodPressureSystolic","input":{"retract":{"type":"HKQuantityTypeIdentifierBloodPressureSystolic"}},"output":{"refused":{"code":"healthkit-input.component-requires-correlation","error":"componentRequiresCorrelation(GroveHealthKitFHIR.HealthKitSourceType.bloodPressureSystolic)","location":"HKSample.sampleType"}}} +{"id":"retraction/HKQuantityTypeIdentifierBodyFatPercentage","input":{"retract":{"type":"HKQuantityTypeIdentifierBodyFatPercentage"}},"output":{"targets":[{"identifier":"v0:test:1:2lrRRHLMevrgCqFOghTeOSpBPtGYPOgWWwvEnQw_ykI","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierBodyMass","input":{"retract":{"type":"HKQuantityTypeIdentifierBodyMass"}},"output":{"targets":[{"identifier":"v0:test:1:KHIaj63a1euv7CMYrGd00b1ocr643EcEZkbVp0oZBzo","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierBodyMassIndex","input":{"retract":{"type":"HKQuantityTypeIdentifierBodyMassIndex"}},"output":{"targets":[{"identifier":"v0:test:1:V_fDbUNnh1fvFKOiulWKg72jVDQCfgz_K6bIiMtzwBo","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierBodyTemperature","input":{"retract":{"type":"HKQuantityTypeIdentifierBodyTemperature"}},"output":{"targets":[{"identifier":"v0:test:1:7MA8gm5QPkq1pyJ7H6M3OdjMBbRRabGwzTnF4dkIJWw","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierCrossCountrySkiingSpeed","input":{"retract":{"type":"HKQuantityTypeIdentifierCrossCountrySkiingSpeed"}},"output":{"targets":[{"identifier":"v0:test:1:DbFfKpTuGqzG1A1ya4uRsSp4zKpp0QcRRuCb2WFrqA0","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierCyclingCadence","input":{"retract":{"type":"HKQuantityTypeIdentifierCyclingCadence"}},"output":{"targets":[{"identifier":"v0:test:1:7AJWSQgnF6nXT0iPe0XPML5H6r6CDVX4roENYy_b__I","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierCyclingFunctionalThresholdPower","input":{"retract":{"type":"HKQuantityTypeIdentifierCyclingFunctionalThresholdPower"}},"output":{"targets":[{"identifier":"v0:test:1:7D30lb2mmkAed-hNEqVypAZrjYHb7dyKmbmiIR170V8","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierCyclingPower","input":{"retract":{"type":"HKQuantityTypeIdentifierCyclingPower"}},"output":{"targets":[{"identifier":"v0:test:1:Xmz3zXpvEj8m8CIC-_ylBhpOzL1rVRJtEMnRnbBJ4n8","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierCyclingSpeed","input":{"retract":{"type":"HKQuantityTypeIdentifierCyclingSpeed"}},"output":{"targets":[{"identifier":"v0:test:1:Z4Aw8UiFKNnQoiocmqYT20bUamrkikdLhmP85Oae_DU","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryBiotin","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryBiotin"}},"output":{"targets":[{"identifier":"v0:test:1:EE0hL53Pij2ifImJviWLqNqgFwsrmKcWeD4rG_2vfZI","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryCaffeine","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryCaffeine"}},"output":{"targets":[{"identifier":"v0:test:1:vA6Ji9m7KOhKcVnUY3Sq_3jLmxLOt4ZnRWoFoTvCTig","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryCalcium","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryCalcium"}},"output":{"targets":[{"identifier":"v0:test:1:i8XeJGI-NmQK2vP5QcUicHFShhhuChAvc14k0hsVO44","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryCarbohydrates","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryCarbohydrates"}},"output":{"targets":[{"identifier":"v0:test:1:umuJToEIwrMJfL2hgkz3Q1fYvDZgf0jdIVQHmSfNYN4","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryChloride","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryChloride"}},"output":{"targets":[{"identifier":"v0:test:1:WdRmU6DTaXqeknrK1-r043vhXAbkhzs9JDpUgYPecN8","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryCholesterol","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryCholesterol"}},"output":{"targets":[{"identifier":"v0:test:1:OrYj4chKZ5k30B548f8eqmAhySq-VMn87n3GKpaCjlM","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryChromium","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryChromium"}},"output":{"targets":[{"identifier":"v0:test:1:1bE2gFvJOQJ8Jnlu3Qi4UnYe5X3XsCFxyxVBVS-J8Ac","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryCopper","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryCopper"}},"output":{"targets":[{"identifier":"v0:test:1:2WUIfWJ9_hLyKI9WkesFZwx8sCtXqoRH65bkpeWM7_Q","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryEnergyConsumed","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}},"output":{"targets":[{"identifier":"v0:test:1:E7RxuoDTC3yyQ5LczmpTxYZwAx4ItqurnUlvu8NeGX4","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryFatMonounsaturated","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryFatMonounsaturated"}},"output":{"targets":[{"identifier":"v0:test:1:wgAGnZb5ri1F9MeRbocbVCJxBrQbUXPHaF13PygVGes","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryFatPolyunsaturated","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryFatPolyunsaturated"}},"output":{"targets":[{"identifier":"v0:test:1:qUUnh4OWxwGkfm4lcrTV1rAsLVym5iTlpn-foABAvuo","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryFatSaturated","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryFatSaturated"}},"output":{"targets":[{"identifier":"v0:test:1:-rySxSiWAQC3w2uENHvOpVNsZ1UjBHNB24ge62IjPK0","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryFatTotal","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryFatTotal"}},"output":{"targets":[{"identifier":"v0:test:1:BHes2Iosm1XXHwLyZwwlXWqKxwkoYG1NemK6TgKTbsc","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryFiber","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryFiber"}},"output":{"targets":[{"identifier":"v0:test:1:qwCgbha1T7QPNoMPo3V5QbQxjB1lSkt131YBR4hmoRc","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryFolate","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryFolate"}},"output":{"targets":[{"identifier":"v0:test:1:_ZnxoxZoCcbTjkN8nCwQ3AKKYqePO5_qoD24Y1Svfmk","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryIodine","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryIodine"}},"output":{"targets":[{"identifier":"v0:test:1:pb9pAIslNgMrTxuMHtYwKXZXxzO4TchevB-VVOOtcdw","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryIron","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryIron"}},"output":{"targets":[{"identifier":"v0:test:1:2O0ZOP9Nva_U09VEdnfszZZc33CtshVX7FeZ-38-R2E","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryMagnesium","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryMagnesium"}},"output":{"targets":[{"identifier":"v0:test:1:YAJkQeP7a2u3eJcqKajNBkr5ZN1HRPZn1ovDxfQ_m7s","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryManganese","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryManganese"}},"output":{"targets":[{"identifier":"v0:test:1:kNXfegnH_KDDXk2FM_WGKb4oILRNnc5q0LLW2qKE4K0","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryMolybdenum","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryMolybdenum"}},"output":{"targets":[{"identifier":"v0:test:1:NAR10gdIUyyFOXU-RLQOyOvgTSz2wuBbebnDAy-K8Tk","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryNiacin","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryNiacin"}},"output":{"targets":[{"identifier":"v0:test:1:fVPjTqMI3nPsRtyYydEB3WhjIJbDMnisUh2ahHX2Yng","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryPantothenicAcid","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryPantothenicAcid"}},"output":{"targets":[{"identifier":"v0:test:1:qLef_ipoXu_S6yv5EtomnWgqZOD2rxkUfBTRTbgINw8","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryPhosphorus","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryPhosphorus"}},"output":{"targets":[{"identifier":"v0:test:1:AFucXtluox31TCMwck_MGVjLpy1_xVU-yz-8Iyf6HlQ","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryPotassium","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryPotassium"}},"output":{"targets":[{"identifier":"v0:test:1:I-9vO6JeKyqon_IxuBGvt_y1ZB2Ny5oX2wnhc6IX8Hg","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryProtein","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryProtein"}},"output":{"targets":[{"identifier":"v0:test:1:p6reW80RhJeTwmziVSl4jmUmY5boyPG9wl8EEpWNEdc","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryRiboflavin","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryRiboflavin"}},"output":{"targets":[{"identifier":"v0:test:1:ucoSXnG7VMqpUZxzCvV6YlkdqieV-KmHkPVwnzbE0DU","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietarySelenium","input":{"retract":{"type":"HKQuantityTypeIdentifierDietarySelenium"}},"output":{"targets":[{"identifier":"v0:test:1:CIfnG0LYoWpER94ppDXaqOMjRxrYrVGLfE6-yxXDzdg","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietarySodium","input":{"retract":{"type":"HKQuantityTypeIdentifierDietarySodium"}},"output":{"targets":[{"identifier":"v0:test:1:79R7JAzcMSqbWpe76mLYsiAmwG-vh6VoZTBsYN3Zkps","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietarySugar","input":{"retract":{"type":"HKQuantityTypeIdentifierDietarySugar"}},"output":{"targets":[{"identifier":"v0:test:1:UnjPFWM4gmy3adNIUUFXJkp6Se8G3v_TbZGlniAEG04","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryThiamin","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryThiamin"}},"output":{"targets":[{"identifier":"v0:test:1:qSUnEf2NjHpizQdqSteVERsmLCyf09w-n1sZuAgiaFo","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryVitaminA","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryVitaminA"}},"output":{"targets":[{"identifier":"v0:test:1:GXgzmitdjdNX5_jvUiGZHXevm5kXa1NsetdZUSIMvn0","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryVitaminB12","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryVitaminB12"}},"output":{"targets":[{"identifier":"v0:test:1:gHkJPX7OM2Z0JuW04W2BHGVP1ko2s2knVjLaYDz0FSc","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryVitaminB6","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryVitaminB6"}},"output":{"targets":[{"identifier":"v0:test:1:-f30hwbizx_mB5FSjPXhdlFYpiXiYtr7FnXxBCtKnVY","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryVitaminC","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryVitaminC"}},"output":{"targets":[{"identifier":"v0:test:1:10BI9cenWmCHyRjh72kHdP839BdynOFEA4Udz0ieM6E","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryVitaminD","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryVitaminD"}},"output":{"targets":[{"identifier":"v0:test:1:SiRDQ9LBYxeUrgGk5k8b_f13o4xbhf78ZV5l5s3vAuA","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryVitaminE","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryVitaminE"}},"output":{"targets":[{"identifier":"v0:test:1:b0XUGZLkKPt3MycOKa2grnkMdGvH8YjLmSh4lN85cLw","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryVitaminK","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryVitaminK"}},"output":{"targets":[{"identifier":"v0:test:1:-6TNvZD6lWyjYuQ2Z_iDL2jTavhsww8fMK7k-6F2LLM","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryWater","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryWater"}},"output":{"targets":[{"identifier":"v0:test:1:1JDUneSpMaw1KoL-z4N6709o5WkH_7NQyLjB0hjMI6E","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDietaryZinc","input":{"retract":{"type":"HKQuantityTypeIdentifierDietaryZinc"}},"output":{"targets":[{"identifier":"v0:test:1:-2IH-vkXQ9hoqGRTrLhvJ18mpGcIjaT7VdiGUPbq0Rs","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDistanceCrossCountrySkiing","input":{"retract":{"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing"}},"output":{"targets":[{"identifier":"v0:test:1:a4JGmZ478fRLECy7SUwd1QYDPpgnrpPrifwF4cKOHwE","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDistanceCycling","input":{"retract":{"type":"HKQuantityTypeIdentifierDistanceCycling"}},"output":{"targets":[{"identifier":"v0:test:1:icoAzYzCP4C240TZetIazH1sFqq426YnNNpk4UHULxQ","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDistanceDownhillSnowSports","input":{"retract":{"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports"}},"output":{"targets":[{"identifier":"v0:test:1:1QrH98Fger7u4NZnZks_tXCrOiDrRQIOEo9K0SCNykU","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDistancePaddleSports","input":{"retract":{"type":"HKQuantityTypeIdentifierDistancePaddleSports"}},"output":{"targets":[{"identifier":"v0:test:1:1ThihyfRtWsYDCkWfM2KqsFVM2CmDmwOcyf44S__gDU","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDistanceRowing","input":{"retract":{"type":"HKQuantityTypeIdentifierDistanceRowing"}},"output":{"targets":[{"identifier":"v0:test:1:-6iO_5zIIaBBdS0lsnI7weVe7bnVxq0eMi3IxbJ5Vd4","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDistanceSkatingSports","input":{"retract":{"type":"HKQuantityTypeIdentifierDistanceSkatingSports"}},"output":{"targets":[{"identifier":"v0:test:1:OL6FVuPJEn01ZNO3ExQhd61uDTAxSUxSjXRdnHhVRHA","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDistanceSwimming","input":{"retract":{"type":"HKQuantityTypeIdentifierDistanceSwimming"}},"output":{"targets":[{"identifier":"v0:test:1:4ESrLdSkiVJOKvjY4BIdbrkEzq0bfvCd1LFlkfDG4GM","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDistanceWalkingRunning","input":{"retract":{"type":"HKQuantityTypeIdentifierDistanceWalkingRunning"}},"output":{"targets":[{"identifier":"v0:test:1:L5qkCNAKPXMoI40QRPkJH7egfW0sMsSLD53NAc-lWLY","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierDistanceWheelchair","input":{"retract":{"type":"HKQuantityTypeIdentifierDistanceWheelchair"}},"output":{"targets":[{"identifier":"v0:test:1:My_5i5foD-eWXcYJRwP16nT2YlJp4BdylhGb8muc4cU","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierElectrodermalActivity","input":{"retract":{"type":"HKQuantityTypeIdentifierElectrodermalActivity"}},"output":{"targets":[{"identifier":"v0:test:1:I0dfsTlDV7cS3ou5tJMEYOC9Cq4qGmGgb9pQJZnwH_g","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierEnvironmentalAudioExposure","input":{"retract":{"type":"HKQuantityTypeIdentifierEnvironmentalAudioExposure"}},"output":{"targets":[{"identifier":"v0:test:1:RfL4MJl3uYaXpJhEXOKYOULzNfc03GSSBlkXIznl5Rw","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierEnvironmentalSoundReduction","input":{"retract":{"type":"HKQuantityTypeIdentifierEnvironmentalSoundReduction"}},"output":{"targets":[{"identifier":"v0:test:1:97_ahzSKvvPVUhbNty4fuPnZKgJZo3GR8JyHGrI4UBA","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierEstimatedWorkoutEffortScore","input":{"retract":{"type":"HKQuantityTypeIdentifierEstimatedWorkoutEffortScore"}},"output":{"targets":[{"identifier":"v0:test:1:ENSe1mUZC3sdttsbkZD_nvMNiwNQtHQ3DIevzfWR2No","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierFlightsClimbed","input":{"retract":{"type":"HKQuantityTypeIdentifierFlightsClimbed"}},"output":{"targets":[{"identifier":"v0:test:1:YHDQhzkmx-9QO2lMmmRZbCyfmi6p08PzP5NZhHSugDA","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierForcedExpiratoryVolume1","input":{"retract":{"type":"HKQuantityTypeIdentifierForcedExpiratoryVolume1"}},"output":{"targets":[{"identifier":"v0:test:1:z8EOWpmonl3DbN_vIKa4g7brtrWFVTmGQe0ZEBL4fQQ","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierForcedVitalCapacity","input":{"retract":{"type":"HKQuantityTypeIdentifierForcedVitalCapacity"}},"output":{"targets":[{"identifier":"v0:test:1:xJQfCdiwEHZ2_MGvfrvawtOxMtcM1fDZG0SYwqR7_2k","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierHeadphoneAudioExposure","input":{"retract":{"type":"HKQuantityTypeIdentifierHeadphoneAudioExposure"}},"output":{"targets":[{"identifier":"v0:test:1:oqkE2zn9ewaKw-kwVsfmfhaQ9y4ZRueSIYOZjpuYego","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierHeartRate","input":{"retract":{"type":"HKQuantityTypeIdentifierHeartRate"}},"output":{"targets":[{"identifier":"v0:test:1:BCDmF07PwhPGl9-EQEJTCAcXAM-B0OSsO_sKoMDE5rE","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierHeartRateRecoveryOneMinute","input":{"retract":{"type":"HKQuantityTypeIdentifierHeartRateRecoveryOneMinute"}},"output":{"targets":[{"identifier":"v0:test:1:Z6bHoOO_Lf6KajuX_0ntb8ZmE2QuMEfWIqWBXemDS2g","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierHeartRateVariabilitySDNN","input":{"retract":{"type":"HKQuantityTypeIdentifierHeartRateVariabilitySDNN"}},"output":{"targets":[{"identifier":"v0:test:1:pGuhDq-GtlpOi8sY0hpcHW1OjPe8kOUnVa_na0LwDCA","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierHeight","input":{"retract":{"type":"HKQuantityTypeIdentifierHeight"}},"output":{"targets":[{"identifier":"v0:test:1:Q8jZlbF4OZJEVGJdQdRShIPnG4cpu7Hcbnctee2vEoE","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierInhalerUsage","input":{"retract":{"type":"HKQuantityTypeIdentifierInhalerUsage"}},"output":{"targets":[{"identifier":"v0:test:1:Tcsei6Wo1Bax7J1LKYiAsSvkmXjtSwVKp1-RK2XLa38","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierInsulinDelivery","input":{"retract":{"type":"HKQuantityTypeIdentifierInsulinDelivery"}},"output":{"targets":[{"identifier":"v0:test:1:b8-BL0CQkqj9OeIPzbdXIjwHSvDlKCZjKAUiECAiKKE","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierLeanBodyMass","input":{"retract":{"type":"HKQuantityTypeIdentifierLeanBodyMass"}},"output":{"targets":[{"identifier":"v0:test:1:VSrpGtie3crVOWrWIsxFTBzDH-G5s0OgICCDu3v-RzM","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierNikeFuel","input":{"retract":{"type":"HKQuantityTypeIdentifierNikeFuel"}},"output":{"refused":{"code":"mobile-input.intentionally-unsupported-source-type","error":"intentionallyUnsupported(GroveHealthKitFHIR.HealthKitSourceType.nikeFuel, reason: \"NikeFuel is an opaque vendor index with an unpublished formula and a retired ecosystem; it has no physiological dimension, no UCUM representation beyond an arbitrary annotation, and no second source, so normalizing it would launder an undefined score into an exchange measurement.\")","location":"HKSample.sampleType"}}} +{"id":"retraction/HKQuantityTypeIdentifierNumberOfAlcoholicBeverages","input":{"retract":{"type":"HKQuantityTypeIdentifierNumberOfAlcoholicBeverages"}},"output":{"targets":[{"identifier":"v0:test:1:yUCp265qNeZmimOneHqY2ozqKmz8tz4R_-EunvCwf0M","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierNumberOfTimesFallen","input":{"retract":{"type":"HKQuantityTypeIdentifierNumberOfTimesFallen"}},"output":{"targets":[{"identifier":"v0:test:1:3v3iPsOhW0rnb7m4sZnF6uo6TytkQrhV8BVYpFzEX-E","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierOxygenSaturation","input":{"retract":{"type":"HKQuantityTypeIdentifierOxygenSaturation"}},"output":{"targets":[{"identifier":"v0:test:1:kJCLgxjnjVCiRnxoQ-t-oaLe4EbL5jv1W2arIvGpfqg","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierPaddleSportsSpeed","input":{"retract":{"type":"HKQuantityTypeIdentifierPaddleSportsSpeed"}},"output":{"targets":[{"identifier":"v0:test:1:vaj2mA6HpVsR4YR2JIT7Lozj17xq7Vqxxqh4YCdiGao","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierPeakExpiratoryFlowRate","input":{"retract":{"type":"HKQuantityTypeIdentifierPeakExpiratoryFlowRate"}},"output":{"targets":[{"identifier":"v0:test:1:MFz_6XL-EE1lL1CLrRZUf1DCUYmjbLIywBl_xwucdu4","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierPeripheralPerfusionIndex","input":{"retract":{"type":"HKQuantityTypeIdentifierPeripheralPerfusionIndex"}},"output":{"targets":[{"identifier":"v0:test:1:E81tjjITJPZKemUVUiHvNwcdGvME1XZgV8UwZFq8sKw","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierPhysicalEffort","input":{"retract":{"type":"HKQuantityTypeIdentifierPhysicalEffort"}},"output":{"targets":[{"identifier":"v0:test:1:H0I-Bs2QyAQo_tGWalRzJq1fWyYDclSyHBPLOXAMzL4","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierPushCount","input":{"retract":{"type":"HKQuantityTypeIdentifierPushCount"}},"output":{"targets":[{"identifier":"v0:test:1:swWRsHJ7ht_4a63-drWvaw0hyqZoeKlzp3RXfrnK5GI","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierRespiratoryRate","input":{"retract":{"type":"HKQuantityTypeIdentifierRespiratoryRate"}},"output":{"targets":[{"identifier":"v0:test:1:PjWL9E0MWw1xJZaMvqQGLYUcytnBQgZGAWJMWCBeyK0","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierRestingHeartRate","input":{"retract":{"type":"HKQuantityTypeIdentifierRestingHeartRate"}},"output":{"targets":[{"identifier":"v0:test:1:yIG4-aaiZHaveNWCsHPy6nKOw1abRtjpbfduLI4gzac","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierRowingSpeed","input":{"retract":{"type":"HKQuantityTypeIdentifierRowingSpeed"}},"output":{"targets":[{"identifier":"v0:test:1:fr-87LJxn0rvQ3KBRCtO-dDUS4yVuCp7B36wW1hAbAU","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierRunningGroundContactTime","input":{"retract":{"type":"HKQuantityTypeIdentifierRunningGroundContactTime"}},"output":{"targets":[{"identifier":"v0:test:1:aLDDHZD-WZAqW8b17N3NnlX-fJHh1ZW6W4tLzBjZHeo","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierRunningPower","input":{"retract":{"type":"HKQuantityTypeIdentifierRunningPower"}},"output":{"targets":[{"identifier":"v0:test:1:VAEA7XXS-6OcrVq_ZyQlb0hzDTli7PnyCggiZ6YJXEA","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierRunningSpeed","input":{"retract":{"type":"HKQuantityTypeIdentifierRunningSpeed"}},"output":{"targets":[{"identifier":"v0:test:1:jMxky9gFzof5e4-C-r7rzq1c0TTXGayR2ICw9mdHuQA","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierRunningStrideLength","input":{"retract":{"type":"HKQuantityTypeIdentifierRunningStrideLength"}},"output":{"targets":[{"identifier":"v0:test:1:BG9v9m_TIn55hL3Cc0O9zboK-sySIu1an18H0dMhnn4","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierRunningVerticalOscillation","input":{"retract":{"type":"HKQuantityTypeIdentifierRunningVerticalOscillation"}},"output":{"targets":[{"identifier":"v0:test:1:mDAluKnXGNjE-UeyKHSBhX9KopcrCWQZZlHld5B1vsg","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierSixMinuteWalkTestDistance","input":{"retract":{"type":"HKQuantityTypeIdentifierSixMinuteWalkTestDistance"}},"output":{"targets":[{"identifier":"v0:test:1:b0Zr1a_bf5kTxKR1cftBkW06JUkTDa0V31Nrl-GcuQE","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierStairAscentSpeed","input":{"retract":{"type":"HKQuantityTypeIdentifierStairAscentSpeed"}},"output":{"targets":[{"identifier":"v0:test:1:j3Wa5MwXLzftbjdhyb7KPnTfeThb4VLhvyJAYlXK19I","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierStairDescentSpeed","input":{"retract":{"type":"HKQuantityTypeIdentifierStairDescentSpeed"}},"output":{"targets":[{"identifier":"v0:test:1:Ct2b7rYVJwUEp_-8g5WJ5LFsqG2hNkxHjTy8HxHO8FY","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierStepCount","input":{"retract":{"type":"HKQuantityTypeIdentifierStepCount"}},"output":{"targets":[{"identifier":"v0:test:1:24MoHdAExhx98wXVl1SiSFSa3iGwCw4jzkNq1ot5sLU","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierSwimmingStrokeCount","input":{"retract":{"type":"HKQuantityTypeIdentifierSwimmingStrokeCount"}},"output":{"targets":[{"identifier":"v0:test:1:13o7szyMMM9vvPUPC3P3axoyzQN9c9l-YdK3QQdVaEI","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierTimeInDaylight","input":{"retract":{"type":"HKQuantityTypeIdentifierTimeInDaylight"}},"output":{"targets":[{"identifier":"v0:test:1:owHWmojP88feTmVli2oQoFgzAS7YKBFXY14v5u4TtnU","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierUVExposure","input":{"retract":{"type":"HKQuantityTypeIdentifierUVExposure"}},"output":{"targets":[{"identifier":"v0:test:1:TEPGgDIb0vLvWeC0tSHLPHz9O6-mgr0ZQUsK8rugzI4","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierUnderwaterDepth","input":{"retract":{"type":"HKQuantityTypeIdentifierUnderwaterDepth"}},"output":{"targets":[{"identifier":"v0:test:1:v1aG_LqrJPbgU1bUbHmaeqcr69zm7-SCMfxfrlSlOUI","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierVO2Max","input":{"retract":{"type":"HKQuantityTypeIdentifierVO2Max"}},"output":{"targets":[{"identifier":"v0:test:1:5TLbUVCfMr0CTfA6ZepwWHAWClohZ-F_l9mlCdmN2jA","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierWaistCircumference","input":{"retract":{"type":"HKQuantityTypeIdentifierWaistCircumference"}},"output":{"targets":[{"identifier":"v0:test:1:IZVkqWtpVky4Kma4vKktj0f7mR4VsmII-0slWPA5Yzc","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierWalkingAsymmetryPercentage","input":{"retract":{"type":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage"}},"output":{"targets":[{"identifier":"v0:test:1:zuwR4uTrlDipCW8Ja2X81jaT4Qc-J85cqyGYnlmkjxQ","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierWalkingDoubleSupportPercentage","input":{"retract":{"type":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage"}},"output":{"targets":[{"identifier":"v0:test:1:flGK88mclfUqADwVs8LcLtZGFiJQpfZcieGreysp2RA","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierWalkingHeartRateAverage","input":{"retract":{"type":"HKQuantityTypeIdentifierWalkingHeartRateAverage"}},"output":{"targets":[{"identifier":"v0:test:1:Qf-cuM-RDSE0xjtJAZ6Dy3pykznPG1P6RVDt6PR-g4c","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierWalkingSpeed","input":{"retract":{"type":"HKQuantityTypeIdentifierWalkingSpeed"}},"output":{"targets":[{"identifier":"v0:test:1:KC1Fpuh79pjCGhd8UmDFqzqRegbtg_w7MPn9zK98zkM","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierWalkingStepLength","input":{"retract":{"type":"HKQuantityTypeIdentifierWalkingStepLength"}},"output":{"targets":[{"identifier":"v0:test:1:_gkB4eKondhZ_41gL9vmRD00pGmLdTcu1GBRhLcHIj8","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierWaterTemperature","input":{"retract":{"type":"HKQuantityTypeIdentifierWaterTemperature"}},"output":{"targets":[{"identifier":"v0:test:1:VfUSaEffxBvgaJdziMiGTllEdfD71ckVIQiHkII-K-s","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKQuantityTypeIdentifierWorkoutEffortScore","input":{"retract":{"type":"HKQuantityTypeIdentifierWorkoutEffortScore"}},"output":{"targets":[{"identifier":"v0:test:1:CKnuZ8UXUOhEaJqWCYP96hTB5ndmqtxjnObDqyVnfdA","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKScoredAssessmentTypeIdentifierGAD7","input":{"retract":{"type":"HKScoredAssessmentTypeIdentifierGAD7"}},"output":{"targets":[{"identifier":"v0:test:1:jJ6ycLKU6-PsPqYTwQIf311qoeIidHNT4aQKTOZvQiI","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKScoredAssessmentTypeIdentifierPHQ9","input":{"retract":{"type":"HKScoredAssessmentTypeIdentifierPHQ9"}},"output":{"targets":[{"identifier":"v0:test:1:zvmbhc8M7iZhYmhD0ZjaGmizzP3mtM_pBk5TV8yEVF0","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"retraction/HKVisionPrescriptionTypeIdentifier","input":{"retract":{"type":"HKVisionPrescriptionTypeIdentifier"}},"output":{"refused":{"code":"mobile-input.platform-exclusive-source-type","error":"platformExclusiveSourceType(GroveHealthKitFHIR.HealthKitSourceType.visionPrescription)","location":"HKSample.sampleType"}}} +{"id":"retraction/HKWorkoutRouteTypeIdentifier","input":{"retract":{"type":"HKWorkoutRouteTypeIdentifier"}},"output":{"targets":[{"identifier":"v0:test:1:w6au7i2r0efFrZdV-FsTqWrjKXcwLHBpB2EKIa6j2Z8","identifierRole":"source-output","resourceType":"DocumentReference","role":"source-artifact"}]}} +{"id":"retraction/HKWorkoutTypeIdentifier","input":{"retract":{"type":"HKWorkoutTypeIdentifier"}},"output":{"targets":[{"identifier":"v0:test:1:yt6gkXLwVlcHbHcKBAw_GHUCMvG_jPCLBIR1lp3XOH8","identifierRole":"source-output","resourceType":"Observation","role":"primary-output"}]}} +{"id":"catalog/entry/HKCategoryTypeIdentifierAbdominalCramps","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierAbdominalCramps"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-abdominal-cramps","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-abdominal-cramps"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-abdominal-cramps"}],"requirement":null,"status":"supported","title":"Abdominal Cramps"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierAcne","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierAcne"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-acne","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-acne"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-acne"}],"requirement":null,"status":"supported","title":"Acne"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierAppetiteChanges","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierAppetiteChanges"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-appetite-changes","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-appetite-changes"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-appetite-changes"}],"requirement":null,"status":"supported","title":"Appetite Changes"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierAppleStandHour","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierAppleStandHour"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"apple-stand-hour","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-stand-hour"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"apple-stand-hour"}],"requirement":null,"status":"supported","title":"Apple Stand Hour"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierAppleWalkingSteadinessEvent","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierAppleWalkingSteadinessEvent"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"walking-steadiness-notification","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-steadiness-notification"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"walking-steadiness-notification"}],"requirement":null,"status":"supported","title":"Apple Walking Steadiness Event"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierAudioExposureEvent","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierAudioExposureEvent"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"environmental-audio-exposure-notification","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-environmental-audio-exposure-notification"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"environmental-audio-exposure-notification"}],"requirement":null,"status":"supported","title":"Audio Exposure Event"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierBladderIncontinence","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierBladderIncontinence"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"bladder-incontinence","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-bladder-incontinence"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"bladder-incontinence"}],"requirement":null,"status":"supported","title":"Bladder Incontinence"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierBleedingAfterPregnancy","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierBleedingAfterPregnancy"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"bleeding-after-pregnancy","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-bleeding-after-pregnancy"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"bleeding-after-pregnancy"}],"requirement":null,"status":"supported","title":"Bleeding After Pregnancy"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierBleedingDuringPregnancy","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierBleedingDuringPregnancy"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"bleeding-during-pregnancy","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-bleeding-during-pregnancy"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"bleeding-during-pregnancy"}],"requirement":null,"status":"supported","title":"Bleeding During Pregnancy"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierBloating","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierBloating"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-bloating","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-bloating"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-bloating"}],"requirement":null,"status":"supported","title":"Bloating"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierBreastPain","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierBreastPain"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-breast-pain","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-breast-pain"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-breast-pain"}],"requirement":null,"status":"supported","title":"Breast Pain"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierCervicalMucusQuality","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierCervicalMucusQuality"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"cervical-mucus-quality","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-cervical-mucus-quality"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"cervical-mucus-quality"}],"requirement":null,"status":"supported","title":"Cervical Mucus Quality"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierChestTightnessOrPain","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierChestTightnessOrPain"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-chest-tightness-or-pain","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-chest-tightness-or-pain"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-chest-tightness-or-pain"}],"requirement":null,"status":"supported","title":"Chest Tightness/Pain"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierChills","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierChills"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-chills","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-chills"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-chills"}],"requirement":null,"status":"supported","title":"Chills"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierConstipation","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierConstipation"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-constipation","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-constipation"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-constipation"}],"requirement":null,"status":"supported","title":"Constipation"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierContraceptive","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierContraceptive"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"contraceptive-use","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-contraceptive-use"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"contraceptive-use"}],"requirement":null,"status":"supported","title":"Contraceptive"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierCoughing","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierCoughing"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-coughing","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-coughing"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-coughing"}],"requirement":null,"status":"supported","title":"Coughing"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierDiarrhea","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierDiarrhea"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-diarrhea","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-diarrhea"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-diarrhea"}],"requirement":null,"status":"supported","title":"Diarrhea"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierDizziness","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierDizziness"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-dizziness","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-dizziness"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-dizziness"}],"requirement":null,"status":"supported","title":"Dizziness"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierDrySkin","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierDrySkin"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-dry-skin","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-dry-skin"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-dry-skin"}],"requirement":null,"status":"supported","title":"Dry Skin"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierFainting","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierFainting"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-fainting","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-fainting"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-fainting"}],"requirement":null,"status":"supported","title":"Fainting"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierFatigue","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierFatigue"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-fatigue","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-fatigue"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-fatigue"}],"requirement":null,"status":"supported","title":"Fatigue"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierFever","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierFever"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-fever","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-fever"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-fever"}],"requirement":null,"status":"supported","title":"Fever"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierGeneralizedBodyAche","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierGeneralizedBodyAche"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-generalized-body-ache","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-generalized-body-ache"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-generalized-body-ache"}],"requirement":null,"status":"supported","title":"Generalized Body Ache"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierHairLoss","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierHairLoss"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-hair-loss","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-hair-loss"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-hair-loss"}],"requirement":null,"status":"supported","title":"Hair Loss"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierHandwashingEvent","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierHandwashingEvent"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"handwashing-session","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-handwashing-session"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"handwashing-session"}],"requirement":null,"status":"supported","title":"Handwashing Event"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierHeadache","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierHeadache"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-headache","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-headache"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-headache"}],"requirement":null,"status":"supported","title":"Headache"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierHeadphoneAudioExposureEvent","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierHeadphoneAudioExposureEvent"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"headphone-audio-exposure-notification","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-headphone-audio-exposure-notification"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"headphone-audio-exposure-notification"}],"requirement":null,"status":"supported","title":"Headphone Audio Exposure Event"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierHeartburn","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierHeartburn"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-heartburn","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-heartburn"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-heartburn"}],"requirement":null,"status":"supported","title":"Heartburn"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierHighHeartRateEvent","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierHighHeartRateEvent"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"high-heart-rate-notification","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-high-heart-rate-notification"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"high-heart-rate-notification"}],"requirement":null,"status":"supported","title":"High Heart Rate Event"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierHotFlashes","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierHotFlashes"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-hot-flashes","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-hot-flashes"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-hot-flashes"}],"requirement":null,"status":"supported","title":"Hot Flashes"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierHypertensionEvent","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierHypertensionEvent"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"hypertension-notification","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-hypertension-notification"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"hypertension-notification"}],"requirement":"Admit only the occurrence of the source platform's proprietary screening notification. The Observation code and result remain HealthKit-specific; no blood-pressure quantity, hypertension diagnosis, clinical finding, threshold, or algorithmic interpretation may be inferred. Cuff blood-pressure quantities remain a separate measurement surface.","status":"supported","title":"Hypertension Event"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierInfrequentMenstrualCycles","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierInfrequentMenstrualCycles"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"infrequent-menstrual-cycles","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-infrequent-menstrual-cycles"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"infrequent-menstrual-cycles"}],"requirement":null,"status":"supported","title":"Infrequent Menstrual Cycles"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierIntermenstrualBleeding","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierIntermenstrualBleeding"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"intermenstrual-bleeding","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-intermenstrual-bleeding"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"intermenstrual-bleeding"}],"requirement":null,"status":"supported","title":"Intermenstrual Bleeding"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierIrregularHeartRhythmEvent","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierIrregularHeartRhythmEvent"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"irregular-heart-rhythm-notification","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-irregular-heart-rhythm-notification"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"irregular-heart-rhythm-notification"}],"requirement":null,"status":"supported","title":"Irregular Heart Rhythm Event"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierIrregularMenstrualCycles","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierIrregularMenstrualCycles"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"irregular-menstrual-cycles","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-irregular-menstrual-cycles"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"irregular-menstrual-cycles"}],"requirement":null,"status":"supported","title":"Irregular Menstrual Cycles"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierLactation","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierLactation"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"lactation-status","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-lactation-status"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"lactation-status"}],"requirement":null,"status":"supported","title":"Lactation"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierLossOfSmell","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierLossOfSmell"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-loss-of-smell","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-loss-of-smell"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-loss-of-smell"}],"requirement":null,"status":"supported","title":"Loss of Smell"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierLossOfTaste","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierLossOfTaste"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-loss-of-taste","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-loss-of-taste"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-loss-of-taste"}],"requirement":null,"status":"supported","title":"Loss of Taste"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierLowCardioFitnessEvent","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierLowCardioFitnessEvent"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"low-cardio-fitness-notification","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-low-cardio-fitness-notification"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"low-cardio-fitness-notification"}],"requirement":null,"status":"supported","title":"Low Cardio Fitness Event"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierLowHeartRateEvent","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierLowHeartRateEvent"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"low-heart-rate-notification","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-low-heart-rate-notification"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"low-heart-rate-notification"}],"requirement":null,"status":"supported","title":"Low Heart Rate Event"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierLowerBackPain","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierLowerBackPain"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-lower-back-pain","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-lower-back-pain"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-lower-back-pain"}],"requirement":null,"status":"supported","title":"Lower Back Pain"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierMemoryLapse","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierMemoryLapse"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-memory-lapse","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-memory-lapse"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-memory-lapse"}],"requirement":null,"status":"supported","title":"Memory Lapse"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierMenstrualFlow","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierMenstrualFlow"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"menstruation-flow","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-menstruation-flow"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"menstruation-flow"}],"requirement":null,"status":"supported","title":"Menstrual Flow"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierMindfulSession","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierMindfulSession"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"mindfulness-session","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-mindfulness-session"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"mindfulness-session"}],"requirement":null,"status":"supported","title":"Mindful Session"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierMoodChanges","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierMoodChanges"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-mood-changes","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-mood-changes"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-mood-changes"}],"requirement":null,"status":"supported","title":"Mood Changes"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierNausea","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierNausea"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-nausea","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-nausea"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-nausea"}],"requirement":null,"status":"supported","title":"Nausea"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierNightSweats","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierNightSweats"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-night-sweats","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-night-sweats"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-night-sweats"}],"requirement":null,"status":"supported","title":"Night Sweats"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierOvulationTestResult","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierOvulationTestResult"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"ovulation-test-result","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-ovulation-test-result"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"ovulation-test-result"}],"requirement":null,"status":"supported","title":"Ovulation Test Result"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierPelvicPain","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierPelvicPain"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-pelvic-pain","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-pelvic-pain"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-pelvic-pain"}],"requirement":null,"status":"supported","title":"Pelvic Pain"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierPersistentIntermenstrualBleeding","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierPersistentIntermenstrualBleeding"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"persistent-intermenstrual-bleeding","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-persistent-intermenstrual-bleeding"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"persistent-intermenstrual-bleeding"}],"requirement":null,"status":"supported","title":"Persistent Intermenstrual Bleeding"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierPregnancy","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierPregnancy"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"pregnancy-status","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-pregnancy-status"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"pregnancy-status"}],"requirement":null,"status":"supported","title":"Pregnancy"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierPregnancyTestResult","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierPregnancyTestResult"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"pregnancy-test-result","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-pregnancy-test-result"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"pregnancy-test-result"}],"requirement":null,"status":"supported","title":"Pregnancy Test Result"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierProgesteroneTestResult","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierProgesteroneTestResult"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"progesterone-test-result","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-progesterone-test-result"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"progesterone-test-result"}],"requirement":null,"status":"supported","title":"Progesterone Test Result"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierProlongedMenstrualPeriods","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierProlongedMenstrualPeriods"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"prolonged-menstrual-periods","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-prolonged-menstrual-periods"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"prolonged-menstrual-periods"}],"requirement":null,"status":"supported","title":"Prolonged Menstrual Periods"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-rapid-pounding-or-fluttering-heartbeat","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-rapid-pounding-or-fluttering-heartbeat"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-rapid-pounding-or-fluttering-heartbeat"}],"requirement":null,"status":"supported","title":"Rapid/Pounding/Fluttering Heartbeat"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierRunnyNose","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierRunnyNose"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-runny-nose","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-runny-nose"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-runny-nose"}],"requirement":null,"status":"supported","title":"Runny Nose"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierSexualActivity","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierSexualActivity"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"sexual-activity","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-sexual-activity"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"sexual-activity"}],"requirement":null,"status":"supported","title":"Sexual Activity"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierShortnessOfBreath","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierShortnessOfBreath"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-shortness-of-breath","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-shortness-of-breath"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-shortness-of-breath"}],"requirement":null,"status":"supported","title":"Shortness of Breath"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierSinusCongestion","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierSinusCongestion"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-sinus-congestion","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-sinus-congestion"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-sinus-congestion"}],"requirement":null,"status":"supported","title":"Sinus Congestion"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierSkippedHeartbeat","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierSkippedHeartbeat"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-skipped-heartbeat","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-skipped-heartbeat"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-skipped-heartbeat"}],"requirement":null,"status":"supported","title":"Skipped Heartbeat"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierSleepAnalysis","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierSleepAnalysis"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"sleep-stage","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-sleep-stage"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"sleep-stage"}],"requirement":null,"status":"supported","title":"Sleep Analysis"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierSleepApneaEvent","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierSleepApneaEvent"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"sleep-apnea-notification","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-sleep-apnea-notification"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"sleep-apnea-notification"}],"requirement":null,"status":"supported","title":"Sleep Apnea Event"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierSleepChanges","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierSleepChanges"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-sleep-changes","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-sleep-changes"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-sleep-changes"}],"requirement":null,"status":"supported","title":"Sleep Changes"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierSoreThroat","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierSoreThroat"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-sore-throat","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-sore-throat"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-sore-throat"}],"requirement":null,"status":"supported","title":"Sore Throat"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierToothbrushingEvent","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierToothbrushingEvent"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"toothbrushing-session","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-toothbrushing-session"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"toothbrushing-session"}],"requirement":null,"status":"supported","title":"Toothbrushing Event"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierVaginalDryness","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierVaginalDryness"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"vaginal-dryness","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-vaginal-dryness"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"vaginal-dryness"}],"requirement":null,"status":"supported","title":"Vaginal Dryness"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierVomiting","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierVomiting"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-vomiting","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-vomiting"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-vomiting"}],"requirement":null,"status":"supported","title":"Vomiting"}} +{"id":"catalog/entry/HKCategoryTypeIdentifierWheezing","input":{"catalog":{"projection":{"entry":{"type":"HKCategoryTypeIdentifierWheezing"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","value":"carried"},"measurements":[{"id":"symptom-wheezing","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-symptom-wheezing"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"symptom-wheezing"}],"requirement":null,"status":"supported","title":"Wheezing"}} +{"id":"catalog/entry/HKCharacteristicTypeIdentifierActivityMoveMode","input":{"catalog":{"projection":{"entry":{"type":"HKCharacteristicTypeIdentifierActivityMoveMode"}}}},"output":{"fieldDispositions":{"value":"withheld"},"measurements":[],"outputs":[],"requirement":"A ring-display preference has no semantically exact Mobile meaning, and converting it would encode an Apple product configuration as clinical data. The mode is interpretive context for the Apple move-time and active-energy rows, which carry their own units and are converted in their own right; it adds no measurement content of its own.","status":"intentionally-unsupported","title":"Activity Move Mode"}} +{"id":"catalog/entry/HKCharacteristicTypeIdentifierBiologicalSex","input":{"catalog":{"projection":{"entry":{"type":"HKCharacteristicTypeIdentifierBiologicalSex"}}}},"output":{"fieldDispositions":{"value":"withheld"},"measurements":[{"id":"biological-sex","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-biological-sex"]}],"outputs":[],"requirement":"Emit the healthkit-biological-sex Observation only for HKBiologicalSex.female, .male, or .other. LOINC 46098-0 'Sex' identifies the observation concept; do not relabel the source as LOINC 76689-9 'Sex assigned at birth', because HealthKit does not assert that provenance. Preserve the exact HealthKit result in the required Grove value set, and emit no Observation for .notSet.","status":"supported","title":"Biological Sex"}} +{"id":"catalog/entry/HKCharacteristicTypeIdentifierBloodType","input":{"catalog":{"projection":{"entry":{"type":"HKCharacteristicTypeIdentifierBloodType"}}}},"output":{"fieldDispositions":{"value":"withheld"},"measurements":[{"id":"blood-type","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-blood-type"]}],"outputs":[],"requirement":null,"status":"supported","title":"Blood Type"}} +{"id":"catalog/entry/HKCharacteristicTypeIdentifierDateOfBirth","input":{"catalog":{"projection":{"entry":{"type":"HKCharacteristicTypeIdentifierDateOfBirth"}}}},"output":{"fieldDispositions":{"value":"withheld"},"measurements":[{"id":"date-of-birth","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-date-of-birth"]}],"outputs":[],"requirement":"The mapping is defined, but disclosure is fail-closed: emit the healthkit-date-of-birth Observation only when deployment policy explicitly authorizes exchanging this direct identifier. Otherwise emit no resource. Never substitute an inferred date, silently reduce precision, or place the value on the pseudonymous exchange Patient; deployments that only require age must derive it under their own approved policy.","status":"supported","title":"Date of Birth"}} +{"id":"catalog/entry/HKCharacteristicTypeIdentifierFitzpatrickSkinType","input":{"catalog":{"projection":{"entry":{"type":"HKCharacteristicTypeIdentifierFitzpatrickSkinType"}}}},"output":{"fieldDispositions":{"value":"withheld"},"measurements":[{"id":"fitzpatrick-skin-type","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-fitzpatrick-skin-type"]}],"outputs":[],"requirement":"Emit the healthkit-fitzpatrick-skin-type Observation only for HealthKit's six stated Fitzpatrick categories, preserving the exact category in the required Grove value set. Treat the value as source-reported classification, not a measured or inferred skin phenotype, and emit no Observation for .notSet.","status":"supported","title":"Fitzpatrick Skin Type"}} +{"id":"catalog/entry/HKCharacteristicTypeIdentifierWheelchairUse","input":{"catalog":{"projection":{"entry":{"type":"HKCharacteristicTypeIdentifierWheelchairUse"}}}},"output":{"fieldDispositions":{"value":"withheld"},"measurements":[{"id":"wheelchair-use","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-wheelchair-use"]}],"outputs":[],"requirement":null,"status":"supported","title":"Wheelchair Use"}} +{"id":"catalog/entry/HKClinicalTypeIdentifierAllergyRecord","input":{"catalog":{"projection":{"entry":{"type":"HKClinicalTypeIdentifierAllergyRecord"}}}},"output":{"fieldDispositions":{"device":"carried","displayName":"withheld","endDate":"carried","fhirResource":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[],"outputs":[{"discriminator":"single","resourceType":"DocumentReference","retractionRole":"source-artifact","role":"clinical-record"}],"requirement":null,"status":"platform-exclusive","title":"Allergy Record"}} +{"id":"catalog/entry/HKClinicalTypeIdentifierClinicalNoteRecord","input":{"catalog":{"projection":{"entry":{"type":"HKClinicalTypeIdentifierClinicalNoteRecord"}}}},"output":{"fieldDispositions":{"device":"carried","displayName":"withheld","endDate":"carried","fhirResource":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[],"outputs":[{"discriminator":"single","resourceType":"DocumentReference","retractionRole":"source-artifact","role":"clinical-record"}],"requirement":null,"status":"platform-exclusive","title":"Clinical Note Record"}} +{"id":"catalog/entry/HKClinicalTypeIdentifierConditionRecord","input":{"catalog":{"projection":{"entry":{"type":"HKClinicalTypeIdentifierConditionRecord"}}}},"output":{"fieldDispositions":{"device":"carried","displayName":"withheld","endDate":"carried","fhirResource":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[],"outputs":[{"discriminator":"single","resourceType":"DocumentReference","retractionRole":"source-artifact","role":"clinical-record"}],"requirement":null,"status":"platform-exclusive","title":"Condition Record"}} +{"id":"catalog/entry/HKClinicalTypeIdentifierCoverageRecord","input":{"catalog":{"projection":{"entry":{"type":"HKClinicalTypeIdentifierCoverageRecord"}}}},"output":{"fieldDispositions":{"device":"carried","displayName":"withheld","endDate":"carried","fhirResource":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[],"outputs":[{"discriminator":"single","resourceType":"DocumentReference","retractionRole":"source-artifact","role":"clinical-record"}],"requirement":null,"status":"platform-exclusive","title":"Coverage Record"}} +{"id":"catalog/entry/HKClinicalTypeIdentifierImmunizationRecord","input":{"catalog":{"projection":{"entry":{"type":"HKClinicalTypeIdentifierImmunizationRecord"}}}},"output":{"fieldDispositions":{"device":"carried","displayName":"withheld","endDate":"carried","fhirResource":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[],"outputs":[{"discriminator":"single","resourceType":"DocumentReference","retractionRole":"source-artifact","role":"clinical-record"}],"requirement":null,"status":"platform-exclusive","title":"Immunization Record"}} +{"id":"catalog/entry/HKClinicalTypeIdentifierLabResultRecord","input":{"catalog":{"projection":{"entry":{"type":"HKClinicalTypeIdentifierLabResultRecord"}}}},"output":{"fieldDispositions":{"device":"carried","displayName":"withheld","endDate":"carried","fhirResource":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[],"outputs":[{"discriminator":"single","resourceType":"DocumentReference","retractionRole":"source-artifact","role":"clinical-record"}],"requirement":null,"status":"platform-exclusive","title":"Lab Result Record"}} +{"id":"catalog/entry/HKClinicalTypeIdentifierMedicationRecord","input":{"catalog":{"projection":{"entry":{"type":"HKClinicalTypeIdentifierMedicationRecord"}}}},"output":{"fieldDispositions":{"device":"carried","displayName":"withheld","endDate":"carried","fhirResource":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[],"outputs":[{"discriminator":"single","resourceType":"DocumentReference","retractionRole":"source-artifact","role":"clinical-record"}],"requirement":null,"status":"platform-exclusive","title":"Medication Record"}} +{"id":"catalog/entry/HKClinicalTypeIdentifierProcedureRecord","input":{"catalog":{"projection":{"entry":{"type":"HKClinicalTypeIdentifierProcedureRecord"}}}},"output":{"fieldDispositions":{"device":"carried","displayName":"withheld","endDate":"carried","fhirResource":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[],"outputs":[{"discriminator":"single","resourceType":"DocumentReference","retractionRole":"source-artifact","role":"clinical-record"}],"requirement":null,"status":"platform-exclusive","title":"Procedure Record"}} +{"id":"catalog/entry/HKClinicalTypeIdentifierVitalSignRecord","input":{"catalog":{"projection":{"entry":{"type":"HKClinicalTypeIdentifierVitalSignRecord"}}}},"output":{"fieldDispositions":{"device":"carried","displayName":"withheld","endDate":"carried","fhirResource":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[],"outputs":[{"discriminator":"single","resourceType":"DocumentReference","retractionRole":"source-artifact","role":"clinical-record"}],"requirement":null,"status":"platform-exclusive","title":"Vital Sign Record"}} +{"id":"catalog/entry/HKCorrelationTypeIdentifierBloodPressure","input":{"catalog":{"projection":{"entry":{"type":"HKCorrelationTypeIdentifierBloodPressure"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","objects":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"blood-pressure","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-pressure"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"blood-pressure"}],"requirement":null,"status":"supported","title":"Blood Pressure"}} +{"id":"catalog/entry/HKCorrelationTypeIdentifierFood","input":{"catalog":{"projection":{"entry":{"type":"HKCorrelationTypeIdentifierFood"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"food-correlation","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-food-correlation"]}],"outputs":[],"requirement":null,"status":"supported","title":"Food"}} +{"id":"catalog/entry/HKDataTypeIdentifierAudiogram","input":{"catalog":{"projection":{"entry":{"type":"HKDataTypeIdentifierAudiogram"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"audiogram-panel","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-audiogram-panel"]}],"outputs":[],"requirement":null,"status":"supported","title":"Audiogram"}} +{"id":"catalog/entry/HKDataTypeIdentifierElectrocardiogram","input":{"catalog":{"projection":{"entry":{"type":"HKDataTypeIdentifierElectrocardiogram"}}}},"output":{"fieldDispositions":{"averageHeartRate":"carried","classification":"carried","device":"carried","endDate":"carried","metadata":"governed","numberOfVoltageMeasurements":"carried","samplingFrequency":"carried","sourceRevision":"carried","startDate":"carried","symptomsStatus":"carried","uuid":"identityOnly","voltageMeasurements":"carried"},"measurements":[{"id":"electrocardiogram","profiles":["https://grovealliance.org/fhir/sensor/StructureDefinition/grove-sensor-ecg-observation","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-ecg-observation"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"electrocardiogram"},{"discriminator":"single","resourceType":"Observation","retractionRole":"child-output","role":"average-heart-rate"}],"requirement":"The caller supplies the HKElectrocardiogram, every voltage measurement with its exact timeSinceSampleStart, and each associated HKCategorySample when symptomsStatus is present. Classification is Observation.interpretation; Apple ECG algorithm version is Observation.method; optional average heart rate is a separate LOINC 8867-4 Observation derived from the waveform. Each supplied symptom is converted through its existing HealthKit symptom Observation profile as a separate source event, and the ECG hasMember carries that Observation's opaque source-output Identifier. Sampling frequency and reported count are validated against SampledData but are not duplicated on the wire. The adapter preserves source and waveform intervals, lead, offsets, and voltages without fetching or resampling.","status":"supported","title":"ECG"}} +{"id":"catalog/entry/HKDataTypeIdentifierHeartbeatSeries","input":{"catalog":{"projection":{"entry":{"type":"HKDataTypeIdentifierHeartbeatSeries"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","heartbeats":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[],"outputs":[{"discriminator":"single","resourceType":"DocumentReference","retractionRole":"source-artifact","role":"native-recording"}],"requirement":"The beat-to-beat interval series is admitted as a recording document carrying the published beat-interval-series column schema. No shared measurement models a beat series, so the samples are carried rather than reduced to a scalar.","status":"platform-exclusive","title":"Heartbeat Series"}} +{"id":"catalog/entry/HKDataTypeStateOfMind","input":{"catalog":{"projection":{"entry":{"type":"HKDataTypeStateOfMind"}}}},"output":{"fieldDispositions":{"associations":"carried","device":"carried","endDate":"carried","kind":"carried","labels":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly","valence":"carried"},"measurements":[{"id":"state-of-mind","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-state-of-mind"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"state-of-mind"}],"requirement":null,"status":"supported","title":"State of Mind"}} +{"id":"catalog/entry/HKDataTypeUserAnnotatedMedicationConcept","input":{"catalog":{"projection":{"entry":{"type":"HKDataTypeUserAnnotatedMedicationConcept"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[],"outputs":[],"requirement":"A non-archived tracked medication is admitted as a MedicationStatement identified by the HKHealthConceptIdentifier of its concept, carrying the person's nickname, the platform's general form, whether a schedule exists, and status active. An archived medication is not admitted, because archival alone does not establish that medication use was completed or stopped.","status":"platform-exclusive","title":"User Annotated Medication Concept"}} +{"id":"catalog/entry/HKDocumentTypeIdentifierCDA","input":{"catalog":{"projection":{"entry":{"type":"HKDocumentTypeIdentifierCDA"}}}},"output":{"fieldDispositions":{"device":"carried","document":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[],"outputs":[{"discriminator":"single","resourceType":"DocumentReference","retractionRole":"source-artifact","role":"clinical-record"}],"requirement":"A CDA document is carried byte-for-byte as a recording document. Grove never asserts conformance over another issuer's document, the same treatment a provider-issued clinical record receives.","status":"platform-exclusive","title":"CDA Document"}} +{"id":"catalog/entry/HKMedicationDoseEventTypeIdentifierMedicationDoseEvent","input":{"catalog":{"projection":{"entry":{"type":"HKMedicationDoseEventTypeIdentifierMedicationDoseEvent"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[],"outputs":[],"requirement":"A logged dose is admitted as a MedicationAdministration that keeps the exact HKMedicationDoseEvent.LogStatus and the schedule it was logged against beside the coarser R4 status; this contract states no mapping from the source case onto an R4 status code, so a consumer reads the log status to learn what the person did. The medication is named by the same HKHealthConceptIdentifier the tracked-medication statement carries.","status":"platform-exclusive","title":"Medication Dose Event"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierActiveEnergyBurned","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierActiveEnergyBurned"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"active-energy","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-active-energy"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"active-energy"}],"requirement":null,"status":"supported","title":"Active Energy Burned"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierAppleExerciseTime","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierAppleExerciseTime"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"apple-exercise-time","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-exercise-time"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"apple-exercise-time"}],"requirement":null,"status":"supported","title":"Apple Exercise Time"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierAppleMoveTime","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierAppleMoveTime"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"apple-move-time","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-move-time"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"apple-move-time"}],"requirement":null,"status":"supported","title":"Apple Move Time"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"sleeping-breathing-disturbances","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-sleeping-breathing-disturbances"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"sleeping-breathing-disturbances"}],"requirement":null,"status":"supported","title":"Apple Sleeping Breathing Disturbances"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierAppleSleepingWristTemperature","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierAppleSleepingWristTemperature"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"skin-temperature","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-skin-temperature"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"skin-temperature"}],"requirement":null,"status":"supported","title":"Apple Sleeping Wrist Temperature"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierAppleStandTime","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierAppleStandTime"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"apple-stand-time","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-apple-stand-time"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"apple-stand-time"}],"requirement":null,"status":"supported","title":"Apple Stand Time"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierAppleWalkingSteadiness","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierAppleWalkingSteadiness"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"walking-steadiness","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-steadiness"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"walking-steadiness"}],"requirement":null,"status":"supported","title":"Apple Walking Steadiness"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierAtrialFibrillationBurden","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierAtrialFibrillationBurden"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"atrial-fibrillation-burden","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-atrial-fibrillation-burden"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"atrial-fibrillation-burden"}],"requirement":null,"status":"supported","title":"AFib Burden"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierBasalBodyTemperature","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierBasalBodyTemperature"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"basal-body-temperature","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-basal-body-temperature"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"basal-body-temperature"}],"requirement":null,"status":"supported","title":"Basal Body Temperature"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierBasalEnergyBurned","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierBasalEnergyBurned"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"basal-energy","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-basal-energy"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"basal-energy"}],"requirement":null,"status":"supported","title":"Basal Energy Burned"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierBloodAlcoholContent","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierBloodAlcoholContent"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"blood-alcohol-content","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-blood-alcohol-content"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"blood-alcohol-content"}],"requirement":null,"status":"supported","title":"Blood Alcohol Content"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierBloodGlucose","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierBloodGlucose"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"blood-glucose-unspecified-specimen","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-blood-glucose-unspecified-specimen"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"blood-glucose-unspecified-specimen"}],"requirement":null,"status":"supported","title":"Blood Glucose"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierBloodPressureDiastolic","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierBloodPressureDiastolic"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[],"outputs":[],"requirement":"A diastolic quantity alone cannot populate the required two-component blood-pressure panel. Convert blood pressure only from HKCorrelationTypeIdentifierBloodPressure.","status":"intentionally-unsupported","title":"Blood Pressure (Diastolic)"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierBloodPressureSystolic","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierBloodPressureSystolic"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[],"outputs":[],"requirement":"A systolic quantity alone cannot populate the required two-component blood-pressure panel. Convert blood pressure only from HKCorrelationTypeIdentifierBloodPressure.","status":"intentionally-unsupported","title":"Blood Pressure (Systolic)"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierBodyFatPercentage","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierBodyFatPercentage"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"body-fat-percentage","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-fat-percentage"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"body-fat-percentage"}],"requirement":null,"status":"supported","title":"Body Fat Percentage"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierBodyMass","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierBodyMass"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"body-weight","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-weight"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"body-weight"}],"requirement":null,"status":"supported","title":"Body Mass"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierBodyMassIndex","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierBodyMassIndex"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"body-mass-index","profiles":["http://hl7.org/fhir/StructureDefinition/bmi","https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-observation"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"body-mass-index"}],"requirement":null,"status":"supported","title":"BMI"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierBodyTemperature","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierBodyTemperature"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"body-temperature","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-temperature"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"body-temperature"}],"requirement":null,"status":"supported","title":"Body Temperature"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierCrossCountrySkiingSpeed","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierCrossCountrySkiingSpeed"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"speed","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"speed"}],"requirement":null,"status":"supported","title":"Cross Country Skiing Speed"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierCyclingCadence","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierCyclingCadence"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"cycling-cadence","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-cycling-cadence"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"cycling-cadence"}],"requirement":null,"status":"supported","title":"Cycling Cadence"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierCyclingFunctionalThresholdPower","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierCyclingFunctionalThresholdPower"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"cycling-functional-threshold-power","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-cycling-functional-threshold-power"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"cycling-functional-threshold-power"}],"requirement":null,"status":"supported","title":"Cycling Functional Threshold Power"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierCyclingPower","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierCyclingPower"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"power","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-power"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"power"}],"requirement":null,"status":"supported","title":"Cycling Power"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierCyclingSpeed","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierCyclingSpeed"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"speed","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"speed"}],"requirement":null,"status":"supported","title":"Cycling Speed"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryBiotin","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryBiotin"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-biotin","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-biotin"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-biotin"}],"requirement":null,"status":"supported","title":"Dietary Biotin Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryCaffeine","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryCaffeine"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-caffeine","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-caffeine"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-caffeine"}],"requirement":null,"status":"supported","title":"Dietary Caffeine Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryCalcium","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryCalcium"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-calcium","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-calcium"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-calcium"}],"requirement":null,"status":"supported","title":"Dietary Calcium Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryCarbohydrates","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryCarbohydrates"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-carbohydrates","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-carbohydrates"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-carbohydrates"}],"requirement":null,"status":"supported","title":"Dietary Carbohydrates Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryChloride","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryChloride"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-chloride","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-chloride"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-chloride"}],"requirement":null,"status":"supported","title":"Dietary Chloride Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryCholesterol","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryCholesterol"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-cholesterol","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-cholesterol"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-cholesterol"}],"requirement":null,"status":"supported","title":"Dietary Cholesterol Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryChromium","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryChromium"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-chromium","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-chromium"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-chromium"}],"requirement":null,"status":"supported","title":"Dietary Chromium Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryCopper","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryCopper"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-copper","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-copper"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-copper"}],"requirement":null,"status":"supported","title":"Dietary Copper Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryEnergyConsumed","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryEnergyConsumed"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-energy","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-energy"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-energy"}],"requirement":null,"status":"supported","title":"Dietary Energy Consumed"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryFatMonounsaturated","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryFatMonounsaturated"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-fat-monounsaturated","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-monounsaturated"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-fat-monounsaturated"}],"requirement":null,"status":"supported","title":"Dietary Monounsaturated Fat Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryFatPolyunsaturated","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryFatPolyunsaturated"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-fat-polyunsaturated","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-polyunsaturated"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-fat-polyunsaturated"}],"requirement":null,"status":"supported","title":"Dietary Polyunsaturated Fat Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryFatSaturated","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryFatSaturated"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-fat-saturated","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-saturated"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-fat-saturated"}],"requirement":null,"status":"supported","title":"Dietary Saturated Fat Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryFatTotal","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryFatTotal"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-fat-total","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fat-total"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-fat-total"}],"requirement":null,"status":"supported","title":"Dietary Total Fat Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryFiber","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryFiber"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-fiber","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-fiber"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-fiber"}],"requirement":null,"status":"supported","title":"Dietary Fiber Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryFolate","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryFolate"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-folate","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-folate"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-folate"}],"requirement":null,"status":"supported","title":"Dietary Folate Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryIodine","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryIodine"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-iodine","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-iodine"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-iodine"}],"requirement":null,"status":"supported","title":"Dietary Iodine Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryIron","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryIron"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-iron","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-iron"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-iron"}],"requirement":null,"status":"supported","title":"Dietary Iron Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryMagnesium","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryMagnesium"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-magnesium","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-magnesium"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-magnesium"}],"requirement":null,"status":"supported","title":"Dietary Magnesium Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryManganese","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryManganese"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-manganese","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-manganese"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-manganese"}],"requirement":null,"status":"supported","title":"Dietary Manganese Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryMolybdenum","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryMolybdenum"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-molybdenum","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-molybdenum"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-molybdenum"}],"requirement":null,"status":"supported","title":"Dietary Molybdenum Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryNiacin","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryNiacin"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-niacin","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-niacin"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-niacin"}],"requirement":null,"status":"supported","title":"Dietary Niacin Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryPantothenicAcid","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryPantothenicAcid"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-pantothenic-acid","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-pantothenic-acid"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-pantothenic-acid"}],"requirement":null,"status":"supported","title":"Dietary Pantothenic Acid Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryPhosphorus","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryPhosphorus"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-phosphorus","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-phosphorus"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-phosphorus"}],"requirement":null,"status":"supported","title":"Dietary Phosphorus Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryPotassium","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryPotassium"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-potassium","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-potassium"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-potassium"}],"requirement":null,"status":"supported","title":"Dietary Potassium Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryProtein","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryProtein"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-protein","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-protein"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-protein"}],"requirement":null,"status":"supported","title":"Dietary Protein Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryRiboflavin","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryRiboflavin"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-riboflavin","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-riboflavin"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-riboflavin"}],"requirement":null,"status":"supported","title":"Dietary Riboflavin Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietarySelenium","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietarySelenium"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-selenium","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-selenium"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-selenium"}],"requirement":null,"status":"supported","title":"Dietary Selenium Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietarySodium","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietarySodium"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-sodium","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-sodium"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-sodium"}],"requirement":null,"status":"supported","title":"Dietary Sodium Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietarySugar","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietarySugar"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-sugar","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-sugar"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-sugar"}],"requirement":null,"status":"supported","title":"Dietary Sugar Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryThiamin","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryThiamin"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-thiamin","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-thiamin"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-thiamin"}],"requirement":null,"status":"supported","title":"Dietary Thiamin Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryVitaminA","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryVitaminA"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-vitamin-a","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-a"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-vitamin-a"}],"requirement":null,"status":"supported","title":"Dietary Vitamin A Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryVitaminB12","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryVitaminB12"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-vitamin-b12","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-b12"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-vitamin-b12"}],"requirement":null,"status":"supported","title":"Dietary Vitamin B12 Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryVitaminB6","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryVitaminB6"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-vitamin-b6","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-b6"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-vitamin-b6"}],"requirement":null,"status":"supported","title":"Dietary Vitamin B6 Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryVitaminC","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryVitaminC"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-vitamin-c","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-c"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-vitamin-c"}],"requirement":null,"status":"supported","title":"Dietary Vitamin C Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryVitaminD","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryVitaminD"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-vitamin-d","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-d"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-vitamin-d"}],"requirement":null,"status":"supported","title":"Dietary Vitamin D Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryVitaminE","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryVitaminE"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-vitamin-e","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-e"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-vitamin-e"}],"requirement":null,"status":"supported","title":"Dietary Vitamin E Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryVitaminK","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryVitaminK"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-vitamin-k","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-vitamin-k"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-vitamin-k"}],"requirement":null,"status":"supported","title":"Dietary Vitamin K Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryWater","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryWater"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"fluid-intake","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-fluid-intake"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"fluid-intake"}],"requirement":null,"status":"supported","title":"Dietary Water Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDietaryZinc","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDietaryZinc"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"dietary-zinc","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-dietary-zinc"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"dietary-zinc"}],"requirement":null,"status":"supported","title":"Dietary Zinc Intake"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDistanceCrossCountrySkiing","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDistanceCrossCountrySkiing"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"distance","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"distance"}],"requirement":null,"status":"supported","title":"Cross-Country Skiing Distance"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDistanceCycling","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDistanceCycling"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"distance","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"distance"}],"requirement":null,"status":"supported","title":"Cycling Distance"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDistanceDownhillSnowSports","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDistanceDownhillSnowSports"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"distance","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"distance"}],"requirement":null,"status":"supported","title":"Downhill Snow Sports Distance"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDistancePaddleSports","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDistancePaddleSports"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"distance","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"distance"}],"requirement":null,"status":"supported","title":"Paddle Sports Distance"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDistanceRowing","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDistanceRowing"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"distance","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"distance"}],"requirement":null,"status":"supported","title":"Rowing Distance"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDistanceSkatingSports","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDistanceSkatingSports"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"distance","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"distance"}],"requirement":null,"status":"supported","title":"Skating Sports Distance"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDistanceSwimming","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDistanceSwimming"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"distance","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"distance"}],"requirement":null,"status":"supported","title":"Swimming Distance"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDistanceWalkingRunning","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDistanceWalkingRunning"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"distance","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"distance"}],"requirement":null,"status":"supported","title":"Distance Walking/Running"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierDistanceWheelchair","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierDistanceWheelchair"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"distance","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-distance"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"distance"}],"requirement":null,"status":"supported","title":"Wheelchair Distance"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierElectrodermalActivity","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierElectrodermalActivity"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"electrodermal-activity","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-electrodermal-activity"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"electrodermal-activity"}],"requirement":null,"status":"supported","title":"Electrodermal Activity"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierEnvironmentalAudioExposure","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierEnvironmentalAudioExposure"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"environmental-audio-exposure","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-environmental-audio-exposure"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"environmental-audio-exposure"}],"requirement":null,"status":"supported","title":"Environmental Audio Exposure"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierEnvironmentalSoundReduction","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierEnvironmentalSoundReduction"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"environmental-sound-reduction","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-environmental-sound-reduction"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"environmental-sound-reduction"}],"requirement":null,"status":"supported","title":"Environmental Sound Reduction"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierEstimatedWorkoutEffortScore","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierEstimatedWorkoutEffortScore"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"workout-effort-score","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-workout-effort-score"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"workout-effort-score"}],"requirement":null,"status":"supported","title":"Estimated Workout Effort"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierFlightsClimbed","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierFlightsClimbed"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"flights-climbed","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-flights-climbed"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"flights-climbed"}],"requirement":null,"status":"supported","title":"Flights Climbed"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierForcedExpiratoryVolume1","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierForcedExpiratoryVolume1"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"forced-expiratory-volume-1","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-forced-expiratory-volume-1"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"forced-expiratory-volume-1"}],"requirement":null,"status":"supported","title":"Forced Expiratory Volume (1 sec)"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierForcedVitalCapacity","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierForcedVitalCapacity"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"forced-vital-capacity","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-forced-vital-capacity"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"forced-vital-capacity"}],"requirement":null,"status":"supported","title":"Forced Vital Capacity"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierHeadphoneAudioExposure","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierHeadphoneAudioExposure"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"headphone-audio-exposure","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-headphone-audio-exposure"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"headphone-audio-exposure"}],"requirement":null,"status":"supported","title":"Headphone Audio Exposure"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierHeartRate","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierHeartRate"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"heart-rate","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"heart-rate"}],"requirement":null,"status":"supported","title":"Heart Rate"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierHeartRateRecoveryOneMinute","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierHeartRateRecoveryOneMinute"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"heart-rate-recovery-one-minute","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-heart-rate-recovery-one-minute"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"heart-rate-recovery-one-minute"}],"requirement":null,"status":"supported","title":"Heart Rate Recovery (1 min)"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierHeartRateVariabilitySDNN","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierHeartRateVariabilitySDNN"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"heart-rate-variability-sdnn","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-heart-rate-variability-sdnn"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"heart-rate-variability-sdnn"}],"requirement":null,"status":"supported","title":"Heart Rate Variability SDNN"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierHeight","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierHeight"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"body-height","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-body-height"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"body-height"}],"requirement":null,"status":"supported","title":"Height"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierInhalerUsage","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierInhalerUsage"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"inhaler-usage","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-inhaler-usage"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"inhaler-usage"}],"requirement":null,"status":"supported","title":"Inhaler Usage"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierInsulinDelivery","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierInsulinDelivery"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"insulin-delivery","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-insulin-delivery"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"insulin-delivery"}],"requirement":null,"status":"supported","title":"Insulin Delivery"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierLeanBodyMass","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierLeanBodyMass"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"lean-body-mass","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-lean-body-mass"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"lean-body-mass"}],"requirement":null,"status":"supported","title":"Lean Body Mass"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierNikeFuel","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierNikeFuel"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[],"outputs":[],"requirement":"NikeFuel is an opaque vendor index with an unpublished formula and a retired ecosystem; it has no physiological dimension, no UCUM representation beyond an arbitrary annotation, and no second source, so normalizing it would launder an undefined score into an exchange measurement.","status":"intentionally-unsupported","title":"NikeFuel"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierNumberOfAlcoholicBeverages","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierNumberOfAlcoholicBeverages"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"number-of-alcoholic-beverages","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-number-of-alcoholic-beverages"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"number-of-alcoholic-beverages"}],"requirement":null,"status":"supported","title":"Number of Alcoholic Beverages"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierNumberOfTimesFallen","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierNumberOfTimesFallen"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"number-of-times-fallen","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-number-of-times-fallen"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"number-of-times-fallen"}],"requirement":null,"status":"supported","title":"Number of Times Fallen"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierOxygenSaturation","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierOxygenSaturation"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"oxygen-saturation","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-oxygen-saturation"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"oxygen-saturation"}],"requirement":null,"status":"supported","title":"Oxygen Saturation"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierPaddleSportsSpeed","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierPaddleSportsSpeed"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"speed","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"speed"}],"requirement":null,"status":"supported","title":"Paddle Sports Speed"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierPeakExpiratoryFlowRate","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierPeakExpiratoryFlowRate"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"peak-expiratory-flow-rate","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-peak-expiratory-flow-rate"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"peak-expiratory-flow-rate"}],"requirement":null,"status":"supported","title":"Peak Expiratory Flow Rate"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierPeripheralPerfusionIndex","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierPeripheralPerfusionIndex"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"peripheral-perfusion-index","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-peripheral-perfusion-index"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"peripheral-perfusion-index"}],"requirement":null,"status":"supported","title":"Peripheral Perfusion Index"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierPhysicalEffort","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierPhysicalEffort"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"physical-effort","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-physical-effort"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"physical-effort"}],"requirement":null,"status":"supported","title":"Physical Effort"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierPushCount","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierPushCount"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"wheelchair-push-count","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-wheelchair-push-count"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"wheelchair-push-count"}],"requirement":null,"status":"supported","title":"Wheelchair Push Count"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierRespiratoryRate","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierRespiratoryRate"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"respiratory-rate","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-respiratory-rate"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"respiratory-rate"}],"requirement":null,"status":"supported","title":"Respiratory Rate"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierRestingHeartRate","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierRestingHeartRate"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"resting-heart-rate","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-resting-heart-rate"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"resting-heart-rate"}],"requirement":null,"status":"supported","title":"Resting Heart Rate"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierRowingSpeed","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierRowingSpeed"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"speed","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"speed"}],"requirement":null,"status":"supported","title":"Rowing Speed"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierRunningGroundContactTime","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierRunningGroundContactTime"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"running-ground-contact-time","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-running-ground-contact-time"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"running-ground-contact-time"}],"requirement":null,"status":"supported","title":"Ground Contact Time"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierRunningPower","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierRunningPower"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"power","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-power"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"power"}],"requirement":null,"status":"supported","title":"Running Power"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierRunningSpeed","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierRunningSpeed"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"speed","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-speed"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"speed"}],"requirement":null,"status":"supported","title":"Running Speed"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierRunningStrideLength","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierRunningStrideLength"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"running-stride-length","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-running-stride-length"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"running-stride-length"}],"requirement":null,"status":"supported","title":"Running Stride Length"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierRunningVerticalOscillation","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierRunningVerticalOscillation"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"running-vertical-oscillation","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-running-vertical-oscillation"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"running-vertical-oscillation"}],"requirement":null,"status":"supported","title":"Running Vertical Oscillation"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierSixMinuteWalkTestDistance","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierSixMinuteWalkTestDistance"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"six-minute-walk-test-distance","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-six-minute-walk-test-distance"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"six-minute-walk-test-distance"}],"requirement":null,"status":"supported","title":"6 Minute Walk Test Distance"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierStairAscentSpeed","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierStairAscentSpeed"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"stair-ascent-speed","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-stair-ascent-speed"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"stair-ascent-speed"}],"requirement":null,"status":"supported","title":"Stair Ascent Speed"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierStairDescentSpeed","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierStairDescentSpeed"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"stair-descent-speed","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-stair-descent-speed"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"stair-descent-speed"}],"requirement":null,"status":"supported","title":"Stair Descent Speed"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierStepCount","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierStepCount"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"step-count","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-step-count"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"step-count"}],"requirement":null,"status":"supported","title":"Step Count"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierSwimmingStrokeCount","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierSwimmingStrokeCount"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"swimming-stroke-count","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-swimming-stroke-count"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"swimming-stroke-count"}],"requirement":null,"status":"supported","title":"Swimming Stroke Count"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierTimeInDaylight","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierTimeInDaylight"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"time-in-daylight","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-time-in-daylight"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"time-in-daylight"}],"requirement":null,"status":"supported","title":"Time in Daylight"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierUVExposure","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierUVExposure"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"uv-exposure","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-uv-exposure"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"uv-exposure"}],"requirement":null,"status":"supported","title":"UV Exposure"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierUnderwaterDepth","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierUnderwaterDepth"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"underwater-depth","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-underwater-depth"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"underwater-depth"}],"requirement":null,"status":"supported","title":"Underwater Depth"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierVO2Max","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierVO2Max"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"vo2-max","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-vo2-max"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"vo2-max"}],"requirement":null,"status":"supported","title":"VO2Max"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierWaistCircumference","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierWaistCircumference"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"waist-circumference","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-waist-circumference"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"waist-circumference"}],"requirement":null,"status":"supported","title":"Waist Circumference"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierWalkingAsymmetryPercentage","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierWalkingAsymmetryPercentage"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"walking-asymmetry","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-asymmetry"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"walking-asymmetry"}],"requirement":null,"status":"supported","title":"Walking Asymmetry Percentage"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierWalkingDoubleSupportPercentage","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierWalkingDoubleSupportPercentage"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"walking-double-support","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-double-support"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"walking-double-support"}],"requirement":null,"status":"supported","title":"Walking Double Support Percentage"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierWalkingHeartRateAverage","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierWalkingHeartRateAverage"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"walking-heart-rate-average","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-heart-rate-average"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"walking-heart-rate-average"}],"requirement":null,"status":"supported","title":"Walking Heart Rate Average"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierWalkingSpeed","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierWalkingSpeed"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"walking-speed","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-speed"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"walking-speed"}],"requirement":null,"status":"supported","title":"Walking Speed"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierWalkingStepLength","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierWalkingStepLength"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"walking-step-length","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-walking-step-length"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"walking-step-length"}],"requirement":null,"status":"supported","title":"Walking Step Length"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierWaterTemperature","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierWaterTemperature"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"water-temperature","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-water-temperature"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"water-temperature"}],"requirement":null,"status":"supported","title":"Water Temperature"}} +{"id":"catalog/entry/HKQuantityTypeIdentifierWorkoutEffortScore","input":{"catalog":{"projection":{"entry":{"type":"HKQuantityTypeIdentifierWorkoutEffortScore"}}}},"output":{"fieldDispositions":{"count":"withheld","device":"carried","endDate":"carried","metadata":"governed","quantity":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"workout-effort-score","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-workout-effort-score"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"workout-effort-score"}],"requirement":null,"status":"supported","title":"Workout Effort"}} +{"id":"catalog/entry/HKScoredAssessmentTypeIdentifierGAD7","input":{"catalog":{"projection":{"entry":{"type":"HKScoredAssessmentTypeIdentifierGAD7"}}}},"output":{"fieldDispositions":{"answers":"withheld","device":"carried","endDate":"carried","metadata":"governed","score":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"gad7-assessment","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-gad7-assessment"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"gad7-assessment"}],"requirement":null,"status":"supported","title":"GAD-7"}} +{"id":"catalog/entry/HKScoredAssessmentTypeIdentifierPHQ9","input":{"catalog":{"projection":{"entry":{"type":"HKScoredAssessmentTypeIdentifierPHQ9"}}}},"output":{"fieldDispositions":{"answers":"withheld","device":"carried","endDate":"carried","metadata":"governed","score":"carried","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[{"id":"phq9-assessment","profiles":["https://grovealliance.org/fhir/healthkit/StructureDefinition/healthkit-phq9-assessment"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"phq9-assessment"}],"requirement":null,"status":"supported","title":"PHQ-9"}} +{"id":"catalog/entry/HKVisionPrescriptionTypeIdentifier","input":{"catalog":{"projection":{"entry":{"type":"HKVisionPrescriptionTypeIdentifier"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[],"outputs":[],"requirement":"A glasses or contacts prescription is admitted as a structured R4 VisionPrescription: the lens specifications map natively, one HKVisionPrism resolves into its vertical and horizontal components, and vertex distance, the two pupillary distances, and the expiration date are represented by extensions. HealthKit supplies no prescriber, so the mandatory reference is stated absent rather than invented.","status":"platform-exclusive","title":"Vision Prescription"}} +{"id":"catalog/entry/HKWorkoutRouteTypeIdentifier","input":{"catalog":{"projection":{"entry":{"type":"HKWorkoutRouteTypeIdentifier"}}}},"output":{"fieldDispositions":{"device":"carried","endDate":"carried","locations":"governed","metadata":"governed","sourceRevision":"carried","startDate":"carried","uuid":"identityOnly"},"measurements":[],"outputs":[{"discriminator":"single","resourceType":"DocumentReference","retractionRole":"source-artifact","role":"native-recording"}],"requirement":"The recorded route is admitted as a recording document carrying the published location-track-samples column schema. A route re-identifies readily, so a producer discloses it only under an explicit route-disclosure authorization.","status":"platform-exclusive","title":"Workout Route"}} +{"id":"catalog/entry/HKWorkoutTypeIdentifier","input":{"catalog":{"projection":{"entry":{"type":"HKWorkoutTypeIdentifier"}}}},"output":{"fieldDispositions":{"device":"carried","duration":"carried","endDate":"carried","metadata":"governed","sourceRevision":"carried","startDate":"carried","statistics":"carried","uuid":"identityOnly","workoutActivities":"withheld","workoutActivityType":"carried","workoutEvents":"withheld"},"measurements":[{"id":"workout","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout"]},{"id":"workout-segment","profiles":["https://grovealliance.org/fhir/mobile/StructureDefinition/grove-mobile-workout-segment"]}],"outputs":[{"discriminator":"single","resourceType":"Observation","retractionRole":"primary-output","role":"workout"}],"requirement":null,"status":"supported","title":"Workout"}} +{"id":"catalog/unit-bindings","input":{"catalog":{"projection":{"unitBindings":{}}}},"output":[{"displayUnit":"kcal","ucumCode":"kcal","unit":"kcal"},{"displayUnit":"min","ucumCode":"min","unit":"min"},{"displayUnit":"Cel","ucumCode":"Cel","unit":"degC"},{"displayUnit":"mg/dL","ucumCode":"mg/dL","unit":"mg/dL"},{"displayUnit":"kg","ucumCode":"kg","unit":"kg"},{"displayUnit":"kg/m2","ucumCode":"kg/m2","unit":"count"},{"displayUnit":"m/s","ucumCode":"m/s","unit":"m/s"},{"displayUnit":"revolutions/minute","ucumCode":"/min","unit":"count/min"},{"displayUnit":"W","ucumCode":"W","unit":"W"},{"displayUnit":"ug","ucumCode":"ug","unit":"mcg"},{"displayUnit":"mg","ucumCode":"mg","unit":"mg"},{"displayUnit":"g","ucumCode":"g","unit":"g"},{"displayUnit":"mL","ucumCode":"mL","unit":"mL"},{"displayUnit":"m","ucumCode":"m","unit":"m"},{"displayUnit":"uS","ucumCode":"uS","unit":"mcS"},{"displayUnit":"dB(SPL)","ucumCode":"dB[SPL]","unit":"dBASPL"},{"displayUnit":"score","ucumCode":"{score}","unit":"appleEffortScore"},{"displayUnit":"flights","ucumCode":"{flights}","unit":"count"},{"displayUnit":"L","ucumCode":"L","unit":"L"},{"displayUnit":"beats/minute","ucumCode":"/min","unit":"count/min"},{"displayUnit":"ms","ucumCode":"ms","unit":"ms"},{"displayUnit":"cm","ucumCode":"cm","unit":"cm"},{"displayUnit":"puffs","ucumCode":"{puff}","unit":"count"},{"displayUnit":"IU","ucumCode":"[iU]","unit":"IU"},{"displayUnit":"drinks","ucumCode":"{drinks}","unit":"count"},{"displayUnit":"falls","ucumCode":"{falls}","unit":"count"},{"displayUnit":"L/min","ucumCode":"L/min","unit":"L/min"},{"displayUnit":"kcal/(kg.h)","ucumCode":"kcal/kg/h","unit":"kcal/hr·kg"},{"displayUnit":"pushes","ucumCode":"{pushes}","unit":"count"},{"displayUnit":"breaths/minute","ucumCode":"/min","unit":"count/min"},{"displayUnit":"steps","ucumCode":"{steps}","unit":"count"},{"displayUnit":"strokes","ucumCode":"{strokes}","unit":"count"},{"displayUnit":"UV index","ucumCode":"{uvindex}","unit":"count"},{"displayUnit":"mL/kg/min","ucumCode":"mL/kg/min","unit":"mL/min·kg"},{"displayUnit":"mmHg","ucumCode":"mm[Hg]","unit":"mmHg"}]} +{"id":"catalog/unit-spellings","input":{"catalog":{"projection":{"unitSpellings":{"spellings":["","%","/h","/min","Cel","IU","L","L/min","UV index","W","[iU]","beats/minute","breaths/minute","cm","dB(SPL)","dB[SPL]","drinks","falls","flights","g","kcal","kcal/(kg.h)","kcal/kg/h","kg","kg/m2","m","m/s","mL","mL/kg/min","mg","mg/dL","min","mmHg","mm[Hg]","ms","not-a-unit","puffs","pushes","revolutions/minute","score","steps","strokes","uS","ug","{drinks}","{falls}","{flights}","{puff}","{pushes}","{score}","{steps}","{strokes}","{uvindex}"]}}}},"output":{"":{"ucumCode":null,"unitSpelling":null},"%":{"ucumCode":null,"unitSpelling":null},"/h":{"ucumCode":null,"unitSpelling":null},"/min":{"ucumCode":"count/min","unitSpelling":"count/min"},"Cel":{"ucumCode":"degC","unitSpelling":"degC"},"IU":{"ucumCode":null,"unitSpelling":"IU"},"L":{"ucumCode":"L","unitSpelling":"L"},"L/min":{"ucumCode":"L/min","unitSpelling":"L/min"},"UV index":{"ucumCode":null,"unitSpelling":"count"},"W":{"ucumCode":"W","unitSpelling":"W"},"[iU]":{"ucumCode":"IU","unitSpelling":"IU"},"beats/minute":{"ucumCode":null,"unitSpelling":"count/min"},"breaths/minute":{"ucumCode":null,"unitSpelling":"count/min"},"cm":{"ucumCode":"cm","unitSpelling":"cm"},"dB(SPL)":{"ucumCode":null,"unitSpelling":"dBASPL"},"dB[SPL]":{"ucumCode":"dBASPL","unitSpelling":"dBASPL"},"drinks":{"ucumCode":null,"unitSpelling":"count"},"falls":{"ucumCode":null,"unitSpelling":"count"},"flights":{"ucumCode":null,"unitSpelling":"count"},"g":{"ucumCode":"g","unitSpelling":"g"},"kcal":{"ucumCode":"kcal","unitSpelling":"kcal"},"kcal/(kg.h)":{"ucumCode":null,"unitSpelling":"kcal/hr·kg"},"kcal/kg/h":{"ucumCode":"kcal/hr·kg","unitSpelling":"kcal/hr·kg"},"kg":{"ucumCode":"kg","unitSpelling":"kg"},"kg/m2":{"ucumCode":"count","unitSpelling":"count"},"m":{"ucumCode":"m","unitSpelling":"m"},"m/s":{"ucumCode":"m/s","unitSpelling":"m/s"},"mL":{"ucumCode":"mL","unitSpelling":"mL"},"mL/kg/min":{"ucumCode":"mL/min·kg","unitSpelling":"mL/min·kg"},"mg":{"ucumCode":"mg","unitSpelling":"mg"},"mg/dL":{"ucumCode":"mg/dL","unitSpelling":"mg/dL"},"min":{"ucumCode":"min","unitSpelling":"min"},"mmHg":{"ucumCode":null,"unitSpelling":"mmHg"},"mm[Hg]":{"ucumCode":"mmHg","unitSpelling":"mmHg"},"ms":{"ucumCode":"ms","unitSpelling":"ms"},"not-a-unit":{"ucumCode":null,"unitSpelling":null},"puffs":{"ucumCode":null,"unitSpelling":"count"},"pushes":{"ucumCode":null,"unitSpelling":"count"},"revolutions/minute":{"ucumCode":null,"unitSpelling":"count/min"},"score":{"ucumCode":null,"unitSpelling":"appleEffortScore"},"steps":{"ucumCode":null,"unitSpelling":"count"},"strokes":{"ucumCode":null,"unitSpelling":"count"},"uS":{"ucumCode":"mcS","unitSpelling":"mcS"},"ug":{"ucumCode":"mcg","unitSpelling":"mcg"},"{drinks}":{"ucumCode":"count","unitSpelling":"count"},"{falls}":{"ucumCode":"count","unitSpelling":"count"},"{flights}":{"ucumCode":"count","unitSpelling":"count"},"{puff}":{"ucumCode":"count","unitSpelling":"count"},"{pushes}":{"ucumCode":"count","unitSpelling":"count"},"{score}":{"ucumCode":"appleEffortScore","unitSpelling":"appleEffortScore"},"{steps}":{"ucumCode":"count","unitSpelling":"count"},"{strokes}":{"ucumCode":"count","unitSpelling":"count"},"{uvindex}":{"ucumCode":"count","unitSpelling":"count"}}} +{"id":"reverse/active-energy","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"active-energy-burned\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"kcal\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"kcal\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"active-energy\")"}}} +{"id":"reverse/basal-body-temperature","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"basal-body-temperature\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"Cel\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"Cel\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 degC","start":"1787005800.0","type":"HKQuantityTypeIdentifierBasalBodyTemperature"}} +{"id":"reverse/basal-energy","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"basal-energy-burned\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"kcal\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"kcal\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"basal-energy\")"}}} +{"id":"reverse/blood-glucose-unspecified-specimen","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"2339-0\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"mg/dL\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mg/dL\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 mg/dL","start":"1787005800.0","type":"HKQuantityTypeIdentifierBloodGlucose"}} +{"id":"reverse/blood-pressure","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"85354-9\",\"system\":\"http://loinc.org\"}]},\"component\":[{\"code\":{\"coding\":[{\"code\":\"8480-6\",\"system\":\"http://loinc.org\"}]},\"valueQuantity\":{\"code\":\"mm[Hg]\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mm[Hg]\",\"value\":120}},{\"code\":{\"coding\":[{\"code\":\"8462-4\",\"system\":\"http://loinc.org\"}]},\"valueQuantity\":{\"code\":\"mm[Hg]\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mm[Hg]\",\"value\":80}}],\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\"}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"objects":[{"end":"1787005800.0","metadata":{},"quantity":"120.0 mmHg","start":"1787005800.0","type":"HKQuantityTypeIdentifierBloodPressureSystolic"},{"end":"1787005800.0","metadata":{},"quantity":"80.0 mmHg","start":"1787005800.0","type":"HKQuantityTypeIdentifierBloodPressureDiastolic"}],"start":"1787005800.0","type":"HKCorrelationTypeIdentifierBloodPressure"}} +{"id":"reverse/body-fat-percentage","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"41982-0\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"%\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"%\",\"value\":50}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"body-fat-percentage\")"}}} +{"id":"reverse/body-height","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"8302-2\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"cm\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"cm\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 cm","start":"1787005800.0","type":"HKQuantityTypeIdentifierHeight"}} +{"id":"reverse/body-temperature","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"8310-5\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"Cel\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"Cel\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 degC","start":"1787005800.0","type":"HKQuantityTypeIdentifierBodyTemperature"}} +{"id":"reverse/body-water-mass","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"101683-1\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"kg\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"kg\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"body-water-mass\")"}}} +{"id":"reverse/body-weight","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"29463-7\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"kg\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"kg\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 kg","start":"1787005800.0","type":"HKQuantityTypeIdentifierBodyMass"}} +{"id":"reverse/bone-mass","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"101685-6\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"kg\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"kg\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"bone-mass\")"}}} +{"id":"reverse/cervical-mucus-quality","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"cervical-mucus-quality\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"cervical-mucus-quality\")"}}} +{"id":"reverse/cycling-cadence","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"cycling-cadence\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"/min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"revolutions/minute\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 count/min","start":"1787005800.0","type":"HKQuantityTypeIdentifierCyclingCadence"}} +{"id":"reverse/deep-sleep-duration","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"93831-6\",\"system\":\"http://loinc.org\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"min\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"deep-sleep-duration\")"}}} +{"id":"reverse/dietary-biotin","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-biotin\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"ug\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"ug\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-biotin\")"}}} +{"id":"reverse/dietary-caffeine","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-caffeine\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"mg\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mg\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-caffeine\")"}}} +{"id":"reverse/dietary-calcium","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-calcium\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"mg\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mg\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-calcium\")"}}} +{"id":"reverse/dietary-carbohydrates","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"9060-5\",\"system\":\"http://loinc.org\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"g\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"g\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-carbohydrates\")"}}} +{"id":"reverse/dietary-chloride","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-chloride\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"mg\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mg\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-chloride\")"}}} +{"id":"reverse/dietary-cholesterol","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-cholesterol\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"mg\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mg\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-cholesterol\")"}}} +{"id":"reverse/dietary-chromium","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-chromium\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"ug\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"ug\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-chromium\")"}}} +{"id":"reverse/dietary-copper","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-copper\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"ug\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"ug\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-copper\")"}}} +{"id":"reverse/dietary-energy","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"9052-2\",\"system\":\"http://loinc.org\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"kcal\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"kcal\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-energy\")"}}} +{"id":"reverse/dietary-fat-monounsaturated","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-fat-monounsaturated\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"g\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"g\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-fat-monounsaturated\")"}}} +{"id":"reverse/dietary-fat-polyunsaturated","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-fat-polyunsaturated\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"g\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"g\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-fat-polyunsaturated\")"}}} +{"id":"reverse/dietary-fat-saturated","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-fat-saturated\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"g\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"g\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-fat-saturated\")"}}} +{"id":"reverse/dietary-fat-total","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"9067-0\",\"system\":\"http://loinc.org\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"g\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"g\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-fat-total\")"}}} +{"id":"reverse/dietary-fiber","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-fiber\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"g\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"g\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-fiber\")"}}} +{"id":"reverse/dietary-folate","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-folate\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"ug\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"ug\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-folate\")"}}} +{"id":"reverse/dietary-iodine","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-iodine\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"ug\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"ug\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-iodine\")"}}} +{"id":"reverse/dietary-iron","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-iron\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"mg\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mg\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-iron\")"}}} +{"id":"reverse/dietary-magnesium","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-magnesium\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"mg\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mg\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-magnesium\")"}}} +{"id":"reverse/dietary-manganese","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-manganese\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"mg\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mg\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-manganese\")"}}} +{"id":"reverse/dietary-molybdenum","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-molybdenum\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"ug\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"ug\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-molybdenum\")"}}} +{"id":"reverse/dietary-niacin","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-niacin\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"mg\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mg\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-niacin\")"}}} +{"id":"reverse/dietary-pantothenic-acid","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-pantothenic-acid\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"mg\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mg\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-pantothenic-acid\")"}}} +{"id":"reverse/dietary-phosphorus","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-phosphorus\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"mg\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mg\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-phosphorus\")"}}} +{"id":"reverse/dietary-potassium","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-potassium\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"mg\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mg\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-potassium\")"}}} +{"id":"reverse/dietary-protein","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"9080-3\",\"system\":\"http://loinc.org\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"g\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"g\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-protein\")"}}} +{"id":"reverse/dietary-riboflavin","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-riboflavin\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"mg\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mg\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-riboflavin\")"}}} +{"id":"reverse/dietary-selenium","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-selenium\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"ug\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"ug\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-selenium\")"}}} +{"id":"reverse/dietary-sodium","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-sodium\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"mg\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mg\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-sodium\")"}}} +{"id":"reverse/dietary-sugar","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-sugar\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"g\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"g\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-sugar\")"}}} +{"id":"reverse/dietary-thiamin","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-thiamin\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"mg\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mg\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-thiamin\")"}}} +{"id":"reverse/dietary-vitamin-a","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-vitamin-a\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"ug\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"ug\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-vitamin-a\")"}}} +{"id":"reverse/dietary-vitamin-b12","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-vitamin-b12\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"ug\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"ug\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-vitamin-b12\")"}}} +{"id":"reverse/dietary-vitamin-b6","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-vitamin-b6\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"mg\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mg\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-vitamin-b6\")"}}} +{"id":"reverse/dietary-vitamin-c","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-vitamin-c\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"mg\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mg\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-vitamin-c\")"}}} +{"id":"reverse/dietary-vitamin-d","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-vitamin-d\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"ug\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"ug\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-vitamin-d\")"}}} +{"id":"reverse/dietary-vitamin-e","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-vitamin-e\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"mg\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mg\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-vitamin-e\")"}}} +{"id":"reverse/dietary-vitamin-k","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-vitamin-k\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"ug\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"ug\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-vitamin-k\")"}}} +{"id":"reverse/dietary-zinc","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"dietary-zinc\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"mg\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mg\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"dietary-zinc\")"}}} +{"id":"reverse/distance","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"103208-5\",\"system\":\"http://loinc.org\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"m\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"m\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"distance\")"}}} +{"id":"reverse/electrodermal-activity","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"electrodermal-activity\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"uS\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"uS\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 mcS","start":"1787005800.0","type":"HKQuantityTypeIdentifierElectrodermalActivity"}} +{"id":"reverse/flights-climbed","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"100304-5\",\"system\":\"http://loinc.org\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"{flights}\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"flights\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"flights-climbed\")"}}} +{"id":"reverse/fluid-intake","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"8985-4\",\"system\":\"http://loinc.org\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"mL\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mL\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"fluid-intake\")"}}} +{"id":"reverse/heart-rate","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"8867-4\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"/min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"beats/minute\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 count/min","start":"1787005800.0","type":"HKQuantityTypeIdentifierHeartRate"}} +{"id":"reverse/heart-rate-variability-rmssd","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"heart-rate-variability-rmssd\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"ms\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"ms\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"heart-rate-variability-rmssd\")"}}} +{"id":"reverse/heart-rate-variability-sdnn","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"112429-6\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"ms\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"ms\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 ms","start":"1787005800.0","type":"HKQuantityTypeIdentifierHeartRateVariabilitySDNN"}} +{"id":"reverse/intermenstrual-bleeding","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"intermenstrual-bleeding\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"intermenstrual-bleeding\")"}}} +{"id":"reverse/lean-body-mass","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"91557-9\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"kg\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"kg\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 kg","start":"1787005800.0","type":"HKQuantityTypeIdentifierLeanBodyMass"}} +{"id":"reverse/light-sleep-duration","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"93830-8\",\"system\":\"http://loinc.org\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"min\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"light-sleep-duration\")"}}} +{"id":"reverse/menstruation-flow","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"menstruation-flow\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"menstruation-flow\")"}}} +{"id":"reverse/mindfulness-session","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"mindfulness-session-duration\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"min\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"mindfulness-session\")"}}} +{"id":"reverse/ovulation-test-result","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"ovulation-test-result\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"ovulation-test-result\")"}}} +{"id":"reverse/oxygen-saturation","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"2708-6\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"%\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"%\",\"value\":50}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"oxygen-saturation\")"}}} +{"id":"reverse/oxygen-saturation-daily-average","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"103209-3\",\"system\":\"http://loinc.org\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"%\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"%\",\"value\":50}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"oxygen-saturation-daily-average\")"}}} +{"id":"reverse/power","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"power\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"W\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"W\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"power\")"}}} +{"id":"reverse/rem-sleep-duration","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"93829-0\",\"system\":\"http://loinc.org\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"min\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"rem-sleep-duration\")"}}} +{"id":"reverse/respiratory-rate","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"9279-1\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"/min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"breaths/minute\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 count/min","start":"1787005800.0","type":"HKQuantityTypeIdentifierRespiratoryRate"}} +{"id":"reverse/respiratory-rate-average","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"103217-6\",\"system\":\"http://loinc.org\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"/min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"breaths/minute\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"respiratory-rate-average\")"}}} +{"id":"reverse/resting-heart-rate","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"40443-4\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"/min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"beats/minute\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 count/min","start":"1787005800.0","type":"HKQuantityTypeIdentifierRestingHeartRate"}} +{"id":"reverse/sexual-activity","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"sexual-activity\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"sexual-activity\")"}}} +{"id":"reverse/skin-temperature","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"61008-9\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"Cel\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"Cel\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 degC","start":"1787005800.0","type":"HKQuantityTypeIdentifierAppleSleepingWristTemperature"}} +{"id":"reverse/sleep-awake-duration","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"93828-2\",\"system\":\"http://loinc.org\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"min\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"sleep-awake-duration\")"}}} +{"id":"reverse/sleep-duration","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"93832-4\",\"system\":\"http://loinc.org\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"h\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"h\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"sleep-duration\")"}}} +{"id":"reverse/sleep-heart-rate","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"sleep-heart-rate\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"/min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"beats/minute\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"sleep-heart-rate\")"}}} +{"id":"reverse/sleep-stage","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"sleep-stage\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"sleep-stage\")"}}} +{"id":"reverse/speed","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"speed\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"m/s\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"m/s\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"speed\")"}}} +{"id":"reverse/step-count","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"step-count-total\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"{steps}\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"steps\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"step-count\")"}}} +{"id":"reverse/vo2-max","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"vo2-max\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"mL/kg/min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mL/kg/min\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 mL/min·kg","start":"1787005800.0","type":"HKQuantityTypeIdentifierVO2Max"}} +{"id":"reverse/wheelchair-push-count","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"96502-0\",\"system\":\"http://loinc.org\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"{pushes}\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"pushes\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"wheelchair-push-count\")"}}} +{"id":"reverse/workout","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"workout\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"workout\")"}}} +{"id":"reverse/workout-segment","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"workout-segment\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-mobile-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"workout-segment\")"}}} +{"id":"reverse/apple-exercise-time","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"apple-exercise-time\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"min\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"apple-exercise-time\")"}}} +{"id":"reverse/apple-move-time","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"apple-move-time\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"min\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"apple-move-time\")"}}} +{"id":"reverse/apple-stand-hour","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"apple-stand-hour\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"apple-stand-hour\")"}}} +{"id":"reverse/apple-stand-time","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"apple-stand-time\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"min\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"apple-stand-time\")"}}} +{"id":"reverse/atrial-fibrillation-burden","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"atrial-fibrillation-burden\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"%\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"%\",\"value\":50}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"atrial-fibrillation-burden\")"}}} +{"id":"reverse/audiogram-panel","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"89015-2\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"audiogram-panel\")"}}} +{"id":"reverse/biological-sex","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"46098-0\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"biological-sex\")"}}} +{"id":"reverse/bladder-incontinence","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"bladder-incontinence\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"bladder-incontinence\")"}}} +{"id":"reverse/bleeding-after-pregnancy","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"bleeding-after-pregnancy\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"bleeding-after-pregnancy\")"}}} +{"id":"reverse/bleeding-during-pregnancy","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"bleeding-during-pregnancy\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"bleeding-during-pregnancy\")"}}} +{"id":"reverse/blood-alcohol-content","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"blood-alcohol-content\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"%\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"%\",\"value\":50}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"blood-alcohol-content\")"}}} +{"id":"reverse/blood-type","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"882-1\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"blood-type\")"}}} +{"id":"reverse/contraceptive-use","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"8659-5\",\"system\":\"http://loinc.org\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"contraceptive-use\")"}}} +{"id":"reverse/cycling-functional-threshold-power","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"cycling-functional-threshold-power\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"W\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"W\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 W","start":"1787005800.0","type":"HKQuantityTypeIdentifierCyclingFunctionalThresholdPower"}} +{"id":"reverse/date-of-birth","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"21112-8\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"date-of-birth\")"}}} +{"id":"reverse/environmental-audio-exposure","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"environmental-audio-exposure\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"dB[SPL]\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"dB(SPL)\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"environmental-audio-exposure\")"}}} +{"id":"reverse/environmental-audio-exposure-notification","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"environmental-audio-exposure-notification\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"environmental-audio-exposure-notification\")"}}} +{"id":"reverse/environmental-sound-reduction","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"environmental-sound-reduction\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"dB[SPL]\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"dB(SPL)\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"environmental-sound-reduction\")"}}} +{"id":"reverse/fitzpatrick-skin-type","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"66555-4\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"fitzpatrick-skin-type\")"}}} +{"id":"reverse/food-correlation","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"food-correlation\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"food-correlation\")"}}} +{"id":"reverse/forced-expiratory-volume-1","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"20150-9\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"L\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"L\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 L","start":"1787005800.0","type":"HKQuantityTypeIdentifierForcedExpiratoryVolume1"}} +{"id":"reverse/forced-vital-capacity","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"19868-9\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"L\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"L\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 L","start":"1787005800.0","type":"HKQuantityTypeIdentifierForcedVitalCapacity"}} +{"id":"reverse/gad7-assessment","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"70274-6\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"{score}\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"score\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"gad7-assessment\")"}}} +{"id":"reverse/handwashing-session","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"handwashing-session\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"s\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"s\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"handwashing-session\")"}}} +{"id":"reverse/headphone-audio-exposure","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"headphone-audio-exposure\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"dB[SPL]\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"dB(SPL)\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"headphone-audio-exposure\")"}}} +{"id":"reverse/headphone-audio-exposure-notification","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"headphone-audio-exposure-notification\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"headphone-audio-exposure-notification\")"}}} +{"id":"reverse/heart-rate-recovery-one-minute","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"heart-rate-recovery-one-minute\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"/min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"beats/minute\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 count/min","start":"1787005800.0","type":"HKQuantityTypeIdentifierHeartRateRecoveryOneMinute"}} +{"id":"reverse/high-heart-rate-notification","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"high-heart-rate-notification\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"high-heart-rate-notification\")"}}} +{"id":"reverse/hypertension-notification","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"hypertension-notification\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"hypertension-notification\")"}}} +{"id":"reverse/infrequent-menstrual-cycles","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"infrequent-menstrual-cycles\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"infrequent-menstrual-cycles\")"}}} +{"id":"reverse/inhaler-usage","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"inhaler-usage\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"{puff}\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"puffs\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"inhaler-usage\")"}}} +{"id":"reverse/insulin-delivery","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"insulin-delivery\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"[iU]\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"IU\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"insulin-delivery\")"}}} +{"id":"reverse/irregular-heart-rhythm-notification","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"irregular-heart-rhythm-notification\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"irregular-heart-rhythm-notification\")"}}} +{"id":"reverse/irregular-menstrual-cycles","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"irregular-menstrual-cycles\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"irregular-menstrual-cycles\")"}}} +{"id":"reverse/lactation-status","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"63895-7\",\"system\":\"http://loinc.org\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"lactation-status\")"}}} +{"id":"reverse/low-cardio-fitness-notification","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"low-cardio-fitness-notification\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"low-cardio-fitness-notification\")"}}} +{"id":"reverse/low-heart-rate-notification","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"low-heart-rate-notification\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"low-heart-rate-notification\")"}}} +{"id":"reverse/number-of-alcoholic-beverages","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"number-of-alcoholic-beverages\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"{drinks}\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"drinks\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"number-of-alcoholic-beverages\")"}}} +{"id":"reverse/number-of-times-fallen","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"number-of-times-fallen\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"{falls}\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"falls\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"number-of-times-fallen\")"}}} +{"id":"reverse/peak-expiratory-flow-rate","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"33452-4\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"L/min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"L/min\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 L/min","start":"1787005800.0","type":"HKQuantityTypeIdentifierPeakExpiratoryFlowRate"}} +{"id":"reverse/peripheral-perfusion-index","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"61006-3\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"%\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"%\",\"value\":50}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"peripheral-perfusion-index\")"}}} +{"id":"reverse/persistent-intermenstrual-bleeding","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"persistent-intermenstrual-bleeding\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"persistent-intermenstrual-bleeding\")"}}} +{"id":"reverse/phq9-assessment","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"44261-6\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"{score}\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"score\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"phq9-assessment\")"}}} +{"id":"reverse/physical-effort","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"physical-effort\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"kcal/kg/h\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"kcal/(kg.h)\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"physical-effort\")"}}} +{"id":"reverse/pregnancy-status","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"82810-3\",\"system\":\"http://loinc.org\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"pregnancy-status\")"}}} +{"id":"reverse/pregnancy-test-result","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"2106-3\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"pregnancy-test-result\")"}}} +{"id":"reverse/progesterone-test-result","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"progesterone-test-result\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"progesterone-test-result\")"}}} +{"id":"reverse/prolonged-menstrual-periods","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"prolonged-menstrual-periods\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"prolonged-menstrual-periods\")"}}} +{"id":"reverse/running-ground-contact-time","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"running-ground-contact-time\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"ms\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"ms\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 ms","start":"1787005800.0","type":"HKQuantityTypeIdentifierRunningGroundContactTime"}} +{"id":"reverse/running-stride-length","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"running-stride-length\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"m\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"m\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 m","start":"1787005800.0","type":"HKQuantityTypeIdentifierRunningStrideLength"}} +{"id":"reverse/running-vertical-oscillation","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"running-vertical-oscillation\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"cm\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"cm\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 cm","start":"1787005800.0","type":"HKQuantityTypeIdentifierRunningVerticalOscillation"}} +{"id":"reverse/six-minute-walk-test-distance","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"64098-7\",\"system\":\"http://loinc.org\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"m\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"m\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"six-minute-walk-test-distance\")"}}} +{"id":"reverse/sleep-apnea-notification","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"sleep-apnea-notification\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"sleep-apnea-notification\")"}}} +{"id":"reverse/sleeping-breathing-disturbances","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"sleeping-breathing-disturbances\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"/h\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"events/hour\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"sleeping-breathing-disturbances\")"}}} +{"id":"reverse/stair-ascent-speed","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"112431-2\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"m/s\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"m/s\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 m/s","start":"1787005800.0","type":"HKQuantityTypeIdentifierStairAscentSpeed"}} +{"id":"reverse/stair-descent-speed","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"112430-4\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"m/s\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"m/s\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 m/s","start":"1787005800.0","type":"HKQuantityTypeIdentifierStairDescentSpeed"}} +{"id":"reverse/state-of-mind","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"state-of-mind\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"valence\",\"value\":0}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"state-of-mind\")"}}} +{"id":"reverse/swimming-stroke-count","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"swimming-stroke-count\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"{strokes}\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"strokes\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"swimming-stroke-count\")"}}} +{"id":"reverse/symptom-abdominal-cramps","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-abdominal-cramps\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-abdominal-cramps\")"}}} +{"id":"reverse/symptom-acne","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-acne\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-acne\")"}}} +{"id":"reverse/symptom-appetite-changes","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-appetite-changes\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-appetite-changes\")"}}} +{"id":"reverse/symptom-bloating","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-bloating\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-bloating\")"}}} +{"id":"reverse/symptom-breast-pain","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-breast-pain\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-breast-pain\")"}}} +{"id":"reverse/symptom-chest-tightness-or-pain","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-chest-tightness-or-pain\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-chest-tightness-or-pain\")"}}} +{"id":"reverse/symptom-chills","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-chills\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-chills\")"}}} +{"id":"reverse/symptom-constipation","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-constipation\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-constipation\")"}}} +{"id":"reverse/symptom-coughing","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-coughing\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-coughing\")"}}} +{"id":"reverse/symptom-diarrhea","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-diarrhea\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-diarrhea\")"}}} +{"id":"reverse/symptom-dizziness","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-dizziness\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-dizziness\")"}}} +{"id":"reverse/symptom-dry-skin","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-dry-skin\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-dry-skin\")"}}} +{"id":"reverse/symptom-fainting","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-fainting\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-fainting\")"}}} +{"id":"reverse/symptom-fatigue","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-fatigue\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-fatigue\")"}}} +{"id":"reverse/symptom-fever","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-fever\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-fever\")"}}} +{"id":"reverse/symptom-generalized-body-ache","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-generalized-body-ache\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-generalized-body-ache\")"}}} +{"id":"reverse/symptom-hair-loss","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-hair-loss\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-hair-loss\")"}}} +{"id":"reverse/symptom-headache","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-headache\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-headache\")"}}} +{"id":"reverse/symptom-heartburn","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-heartburn\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-heartburn\")"}}} +{"id":"reverse/symptom-hot-flashes","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-hot-flashes\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-hot-flashes\")"}}} +{"id":"reverse/symptom-loss-of-smell","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-loss-of-smell\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-loss-of-smell\")"}}} +{"id":"reverse/symptom-loss-of-taste","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-loss-of-taste\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-loss-of-taste\")"}}} +{"id":"reverse/symptom-lower-back-pain","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-lower-back-pain\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-lower-back-pain\")"}}} +{"id":"reverse/symptom-memory-lapse","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-memory-lapse\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-memory-lapse\")"}}} +{"id":"reverse/symptom-mood-changes","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-mood-changes\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-mood-changes\")"}}} +{"id":"reverse/symptom-nausea","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"81660-3\",\"system\":\"http://loinc.org\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-nausea\")"}}} +{"id":"reverse/symptom-night-sweats","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-night-sweats\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-night-sweats\")"}}} +{"id":"reverse/symptom-pelvic-pain","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-pelvic-pain\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-pelvic-pain\")"}}} +{"id":"reverse/symptom-rapid-pounding-or-fluttering-heartbeat","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-rapid-pounding-or-fluttering-heartbeat\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-rapid-pounding-or-fluttering-heartbeat\")"}}} +{"id":"reverse/symptom-runny-nose","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-runny-nose\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-runny-nose\")"}}} +{"id":"reverse/symptom-shortness-of-breath","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-shortness-of-breath\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-shortness-of-breath\")"}}} +{"id":"reverse/symptom-sinus-congestion","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-sinus-congestion\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-sinus-congestion\")"}}} +{"id":"reverse/symptom-skipped-heartbeat","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-skipped-heartbeat\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-skipped-heartbeat\")"}}} +{"id":"reverse/symptom-sleep-changes","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-sleep-changes\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-sleep-changes\")"}}} +{"id":"reverse/symptom-sore-throat","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-sore-throat\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-sore-throat\")"}}} +{"id":"reverse/symptom-vomiting","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-vomiting\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-vomiting\")"}}} +{"id":"reverse/symptom-wheezing","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"symptom-wheezing\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"symptom-wheezing\")"}}} +{"id":"reverse/time-in-daylight","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"time-in-daylight\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"min\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"time-in-daylight\")"}}} +{"id":"reverse/toothbrushing-session","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"toothbrushing-session\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"s\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"s\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"toothbrushing-session\")"}}} +{"id":"reverse/underwater-depth","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"underwater-depth\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"m\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"m\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 m","start":"1787005800.0","type":"HKQuantityTypeIdentifierUnderwaterDepth"}} +{"id":"reverse/uv-exposure","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"uv-exposure\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"{uvindex}\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"UV index\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"uv-exposure\")"}}} +{"id":"reverse/vaginal-dryness","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"vaginal-dryness\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"vaginal-dryness\")"}}} +{"id":"reverse/waist-circumference","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"8280-0\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"cm\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"cm\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 cm","start":"1787005800.0","type":"HKQuantityTypeIdentifierWaistCircumference"}} +{"id":"reverse/walking-asymmetry","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"112432-0\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"%\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"%\",\"value\":50}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"walking-asymmetry\")"}}} +{"id":"reverse/walking-double-support","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"112434-6\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"%\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"%\",\"value\":50}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"walking-double-support\")"}}} +{"id":"reverse/walking-heart-rate-average","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"walking-heart-rate-average\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"/min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"beats/minute\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"walking-heart-rate-average\")"}}} +{"id":"reverse/walking-speed","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"walking-speed\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"m/s\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"m/s\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 m/s","start":"1787005800.0","type":"HKQuantityTypeIdentifierWalkingSpeed"}} +{"id":"reverse/walking-steadiness","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"walking-steadiness\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"%\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"%\",\"value\":50}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"walking-steadiness\")"}}} +{"id":"reverse/walking-steadiness-notification","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"walking-steadiness-notification\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"walking-steadiness-notification\")"}}} +{"id":"reverse/walking-step-length","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"walking-step-length\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"cm\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"cm\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 cm","start":"1787005800.0","type":"HKQuantityTypeIdentifierWalkingStepLength"}} +{"id":"reverse/water-temperature","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"water-temperature\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"Cel\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"Cel\",\"value\":1}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"1.0 degC","start":"1787005800.0","type":"HKQuantityTypeIdentifierWaterTemperature"}} +{"id":"reverse/wheelchair-use","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"wheelchair-use\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"1\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"1\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementNotMappable(id: \"wheelchair-use\")"}}} +{"id":"reverse/workout-effort-score","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"workout-effort-score\",\"system\":\"https://grovealliance.org/fhir/healthkit/CodeSystem/healthkit-measurement\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:31:00-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"{score}\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"score\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"workout-effort-score\")"}}} +{"id":"reverse/body-mass-index","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"39156-5\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"kg/m2\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"kg/m2\",\"value\":1}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementUnknown(system: \"http://loinc.org\", code: \"39156-5\")"}}} +{"id":"reverse/edge/period","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"8867-4\",\"system\":\"http://loinc.org\"}]},\"effectivePeriod\":{\"end\":\"2026-08-17T15:30:45-07:00\",\"start\":\"2026-08-17T15:30:00-07:00\"},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"/min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"beats/minute\",\"value\":72}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"heart-rate\")"}}} +{"id":"reverse/edge/no-effective","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"8867-4\",\"system\":\"http://loinc.org\"}]},\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"/min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"beats/minute\",\"value\":72}}"}}}},"output":{"refused":{"code":"mobile-input.effective-period-invalid","error":"effectiveMissing(id: \"heart-rate\")"}}} +{"id":"reverse/edge/no-value","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"8867-4\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\"}"}}}},"output":{"refused":{"code":"mobile-input.value-shape-invalid","error":"valueMissing(id: \"heart-rate\")"}}} +{"id":"reverse/edge/unit-code-mismatch","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"8867-4\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"/s\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"beats/second\",\"value\":1.2}}"}}}},"output":{"refused":{"code":"mobile-output.fixed-quantity-unit","error":"unitNotMappable(code: \"/s\")"}}} +{"id":"reverse/edge/unit-system-mismatch","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"8867-4\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"/min\",\"system\":\"https://example.org/units\",\"unit\":\"beats/minute\",\"value\":72}}"}}}},"output":{"refused":{"code":"mobile-output.fixed-quantity-unit","error":"unitNotMappable(code: \"/min\")"}}} +{"id":"reverse/edge/unknown-code","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"0000-0\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"/min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"beats/minute\",\"value\":72}}"}}}},"output":{"refused":{"code":"mobile-input.unsupported-source-type","error":"measurementUnknown(system: \"http://loinc.org\", code: \"0000-0\")"}}} +{"id":"reverse/edge/decimal-value","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"8867-4\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"/min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"beats/minute\",\"value\":72.5}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700"},"quantity":"72.5 count/min","start":"1787005800.0","type":"HKQuantityTypeIdentifierHeartRate"}} +{"id":"reverse/edge/utc","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"8867-4\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T22:30:00Z\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"/min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"beats/minute\",\"value\":72}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT"},"quantity":"72.0 count/min","start":"1787005800.0","type":"HKQuantityTypeIdentifierHeartRate"}} +{"id":"reverse/edge/fraction","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"8867-4\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T22:30:00.250Z\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"/min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"beats/minute\",\"value\":72}}"}}}},"output":{"end":"1787005800.25","metadata":{"HKTimeZone":"GMT"},"quantity":"72.0 count/min","start":"1787005800.25","type":"HKQuantityTypeIdentifierHeartRate"}} +{"id":"reverse/edge/date-only","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"8867-4\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"/min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"beats/minute\",\"value\":72}}"}}}},"output":{"end":"1786924800.0","metadata":{},"quantity":"72.0 count/min","start":"1786924800.0","type":"HKQuantityTypeIdentifierHeartRate"}} +{"id":"reverse/edge/pre-reform","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"8867-4\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"1500-01-01T00:00:00Z\",\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"/min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"beats/minute\",\"value\":72}}"}}}},"output":{"end":"-14830992000.0","metadata":{"HKTimeZone":"GMT"},"quantity":"72.0 count/min","start":"-14830992000.0","type":"HKQuantityTypeIdentifierHeartRate"}} +{"id":"reverse/edge/manual-entry","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"8867-4\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"extension\":[{\"url\":\"https://grovealliance.org/fhir/mobile/StructureDefinition/grove-recording-method\",\"valueCoding\":{\"code\":\"manual-entry\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-recording-method\"}}],\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"/min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"beats/minute\",\"value\":72}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKTimeZone":"GMT-0700","HKWasUserEntered":"1"},"quantity":"72.0 count/min","start":"1787005800.0","type":"HKQuantityTypeIdentifierHeartRate"}} +{"id":"reverse/edge/sync-identity","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"8867-4\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"extension\":[{\"url\":\"https://grovealliance.org/fhir/mobile/StructureDefinition/grove-writer-record-version\",\"valueString\":\"5\"}],\"identifier\":[{\"system\":\"https://example.org/source-output\",\"type\":{\"coding\":[{\"code\":\"source-output\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role\"}]},\"value\":\"output-1\"}],\"resourceType\":\"Observation\",\"status\":\"final\",\"valueQuantity\":{\"code\":\"/min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"beats/minute\",\"value\":72}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKMetadataKeySyncIdentifier":"output-1","HKMetadataKeySyncVersion":"5","HKTimeZone":"GMT-0700"},"quantity":"72.0 count/min","start":"1787005800.0","type":"HKQuantityTypeIdentifierHeartRate"}} +{"id":"reverse/edge/amended-sync-identity","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"8867-4\",\"system\":\"http://loinc.org\"}]},\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"identifier\":[{\"system\":\"https://example.org/source-output\",\"type\":{\"coding\":[{\"code\":\"source-output\",\"system\":\"https://grovealliance.org/fhir/mobile/CodeSystem/grove-identifier-role\"}]},\"value\":\"output-1\"}],\"resourceType\":\"Observation\",\"status\":\"amended\",\"valueQuantity\":{\"code\":\"/min\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"beats/minute\",\"value\":72}}"}}}},"output":{"end":"1787005800.0","metadata":{"HKMetadataKeySyncIdentifier":"output-1","HKMetadataKeySyncVersion":"2","HKTimeZone":"GMT-0700"},"quantity":"72.0 count/min","start":"1787005800.0","type":"HKQuantityTypeIdentifierHeartRate"}} +{"id":"reverse/edge/blood-pressure-missing-diastolic","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"85354-9\",\"system\":\"http://loinc.org\"}]},\"component\":[{\"code\":{\"coding\":[{\"code\":\"8480-6\",\"system\":\"http://loinc.org\"}]},\"valueQuantity\":{\"code\":\"mm[Hg]\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"mm[Hg]\",\"value\":120}}],\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\"}"}}}},"output":{"refused":{"code":"mobile-input.required-component-missing","error":"componentMissing(id: \"blood-pressure\", code: \"8462-4\")"}}} +{"id":"reverse/edge/blood-pressure-unit-mismatch","input":{"catalog":{"projection":{"reverse":{"observation":"{\"code\":{\"coding\":[{\"code\":\"85354-9\",\"system\":\"http://loinc.org\"}]},\"component\":[{\"code\":{\"coding\":[{\"code\":\"8480-6\",\"system\":\"http://loinc.org\"}]},\"valueQuantity\":{\"code\":\"kPa\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"kPa\",\"value\":120}},{\"code\":{\"coding\":[{\"code\":\"8462-4\",\"system\":\"http://loinc.org\"}]},\"valueQuantity\":{\"code\":\"kPa\",\"system\":\"http://unitsofmeasure.org\",\"unit\":\"kPa\",\"value\":80}}],\"effectiveDateTime\":\"2026-08-17T15:30:00-07:00\",\"resourceType\":\"Observation\",\"status\":\"final\"}"}}}},"output":{"refused":{"code":"mobile-output.fixed-quantity-unit","error":"unitNotMappable(code: \"kPa\")"}}} diff --git a/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift b/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift index 7549a5772..eeebcb0ba 100644 --- a/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift +++ b/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift @@ -13,9 +13,58 @@ import HealthKit import ObjectiveC +/// TEST-ONLY. An `HKElectrocardiogram` that states its whole reading itself. +/// +/// HealthKit keeps an ECG's voltage count and sampling frequency in a C++ reading key-value coding cannot reach, +/// and derives its classification from a private enumeration, so a stored ECG answers those five properties +/// from the reading `StoredSampleFixtures.electrocardiogram(shape:reading:)` attaches. Every other fact lives +/// where HealthKit keeps it. +final class StoredElectrocardiogram: HKElectrocardiogram, @unchecked Sendable { + /// What an ECG reports about its recording. + struct Reading: Sendable { + var classification: HKElectrocardiogram.Classification + var symptomsStatus: HKElectrocardiogram.SymptomsStatus + var numberOfVoltageMeasurements: Int + var averageHeartRate: HKQuantity? + var samplingFrequency: HKQuantity? + } + + /// The reading, as an object the runtime can associate with the instance. + private final class Statement: NSObject { + let reading: Reading + + init(_ reading: Reading) { + self.reading = reading + } + } + + /// The association key; only its address matters. + nonisolated(unsafe) private static var readingKey: UInt8 = 0 + + override var classification: Classification { reading.classification } + override var symptomsStatus: SymptomsStatus { reading.symptomsStatus } + override var numberOfVoltageMeasurements: Int { reading.numberOfVoltageMeasurements } + override var averageHeartRate: HKQuantity? { reading.averageHeartRate } + override var samplingFrequency: HKQuantity? { reading.samplingFrequency } + + private var reading: Reading { + guard let statement = objc_getAssociatedObject(self, &Self.readingKey) as? Statement else { + preconditionFailure("A stored ECG states its reading when it is built") + } + return statement.reading + } + + /// Attaches the reading every overridden property answers from. + func state(_ reading: Reading) { + objc_setAssociatedObject(self, &Self.readingKey, Statement(reading), .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } +} + + /// TEST-ONLY. Builds HealthKit samples the way the store hands them back: with a chosen UUID, an /// attributable `HKSourceRevision`, and (for the series classes HealthKit offers no synthetic -/// initializer for) chosen dates, device and metadata. +/// initializer for) chosen dates, device and metadata. The content corpus also restates facts +/// HealthKit refuses when it creates a sample, and states ECG readings and voltages. /// /// HealthKit's public factories mint a fresh UUID and attribute every sample to the running /// process, so no test can otherwise pin a graph whose identities derive from the UUID, or one that @@ -124,20 +173,53 @@ enum StoredSampleFixtures { static func seriesSample(_ type: Sample.Type, sampleType: HKSampleType, shape: SeriesShape) throws -> Sample { let object = try allocate(type) try write(sampleType, to: "sampleType", of: object) - try write(NSNumber(value: shape.start.timeIntervalSinceReferenceDate), to: "startTimestamp", of: object) - try write(NSNumber(value: shape.end.timeIntervalSinceReferenceDate), to: "endTimestamp", of: object) - try write(shape.device, to: "device", of: object) - try write(shape.metadata, to: "metadata", of: object) - let sample = try stored(unsafeDowncast(object, to: type), uuid: shape.uuid, writer: shape.writer) - guard sample.sampleType == sampleType, sample.startDate == shape.start, sample.endDate == shape.end else { - throw FixtureError.keyNotHonored(key: "sampleType/startTimestamp/endTimestamp", class: String(describing: type)) - } - guard sample.device == shape.device, (sample.metadata ?? [:]).keys.sorted() == (shape.metadata ?? [:]).keys.sorted() else { - throw FixtureError.keyNotHonored(key: "device/metadata", class: String(describing: type)) + let sample = try restated(unsafeDowncast(object, to: type), shape: shape) + guard sample.sampleType == sampleType else { + throw FixtureError.keyNotHonored(key: "sampleType", class: String(describing: type)) } return sample } + /// `sample` carrying exactly `shape`'s facts in place of the ones its initializer stated. + /// + /// HealthKit validates a sample only when it creates one, so a fact it refuses there (a reversed interval, + /// a metadata value of the wrong type, an instant after 4000) can be stated only afterwards, as here. + static func restated(_ sample: Sample, shape: SeriesShape) throws -> Sample { + try write(NSNumber(value: shape.start.timeIntervalSinceReferenceDate), to: "startTimestamp", of: sample) + try write(NSNumber(value: shape.end.timeIntervalSinceReferenceDate), to: "endTimestamp", of: sample) + try write(shape.device, to: "device", of: sample) + try write(shape.metadata, to: "metadata", of: sample) + let stored = try stored(sample, uuid: shape.uuid, writer: shape.writer) + let name = String(describing: type(of: sample)) + guard stored.startDate == shape.start, stored.endDate == shape.end else { + throw FixtureError.keyNotHonored(key: "startTimestamp/endTimestamp", class: name) + } + guard stored.device == shape.device, (stored.metadata ?? [:]).keys.sorted() == (shape.metadata ?? [:]).keys.sorted() else { + throw FixtureError.keyNotHonored(key: "device/metadata", class: name) + } + return stored + } + + /// An ECG carrying exactly `shape` and stating `reading` as HealthKit would report it. + static func electrocardiogram(shape: SeriesShape, reading: StoredElectrocardiogram.Reading) throws -> HKElectrocardiogram { + let ecg = try seriesSample(StoredElectrocardiogram.self, sampleType: HKObjectType.electrocardiogramType(), shape: shape) + ecg.state(reading) + return ecg + } + + /// One voltage of an ECG's lead, or a measurement that states no lead voltage at all. + static func voltageMeasurement(offset: TimeInterval, millivolts: Double?) throws -> HKElectrocardiogram.VoltageMeasurement { + let object = try allocate(HKElectrocardiogram.VoltageMeasurement.self) + try write(NSNumber(value: offset), to: "timeSinceSampleStart", of: object) + try write(millivolts.map { HKQuantity(unit: .voltUnit(with: .milli), doubleValue: $0) }, to: "leadIVoltage", of: object) + let measurement = unsafeDowncast(object, to: HKElectrocardiogram.VoltageMeasurement.self) + guard measurement.timeSinceSampleStart.bitPattern == offset.bitPattern, + (measurement.quantity(for: .appleWatchSimilarToLeadI) == nil) == (millivolts == nil) else { + throw FixtureError.keyNotHonored(key: "timeSinceSampleStart/leadIVoltage", class: "HKElectrocardiogram.VoltageMeasurement") + } + return measurement + } + /// An `HKElectrocardiogram` reading `shape`'s facts, its classification, symptoms status and average heart rate. /// Its voltages are HealthKit's private storage and stay unset, so it reports no measurement count and no sampling /// frequency. HealthKit keeps the classification under a private numbering: `reading` names that number and the @@ -194,14 +276,16 @@ enum StoredSampleFixtures { && ["name", "bundleIdentifier"].allSatisfy { class_getInstanceVariable(HKSource.self, "_\($0)") != nil } } - private static func allocate(_ type: AnyClass) throws -> NSObject { + /// A bare instance of `type`, none of whose initializers ran. + static func allocate(_ type: AnyClass) throws -> NSObject { guard let object = class_createInstance(type, 0) as? NSObject else { throw FixtureError.classNotConstructible(String(describing: type)) } return object } - private static func write(_ value: Any?, to key: String, of object: NSObject) throws { + /// Writes one private ivar through key-value coding, failing when the class no longer has it. + static func write(_ value: Any?, to key: String, of object: NSObject) throws { guard class_getInstanceVariable(type(of: object), "_\(key)") != nil else { throw FixtureError.keyNotHonored(key: key, class: String(describing: type(of: object))) } From c177ac05eaba15d2514bbbf83e68178f90a69174 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sat, 3 Oct 2026 22:09:43 +0200 Subject: [PATCH 053/220] Keep HealthKit's Private Storage in the Fixtures and Guard the Content Corpus Follow-up to 29cbbfab (track 3, M0): the fixture-safety, tooling and design findings of the two M0 reviews (brief sections B6, B11, B13 and C1-C14). Tests only; no file under Sources/ changes, and neither the corpus nor any golden changes. Stored-sample fixtures (C1, C6): - Every write and read of HealthKit's private storage now goes through StoredSampleFixtures, gated by one key table per class (HKObject, HKSample, HKSource, HKQuantitySample, HKCategorySample, HKCorrelation, HKWorkout, HKWorkoutActivity, HKStatistics, HKStateOfMind, HKScoredAssessment, the ECG voltage measurement, and off watchOS the CDA and clinical classes). allocate/write are private again; instance(of:stating:), restate(_:with:) and read(_:of:) refuse an undeclared key (keyNotDeclared) and a key the class no longer has (keyNotHonored), so the three unguarded value(forKey:) reads that could crash the xctest process are gone; privateStorageIsPresent checks the whole table. - The per-class builders the corpus used (quantity, category, correlation, workout with statistics, State of Mind, scored assessment, CDA document, clinical record, ECG, voltage) moved into StoredSampleFixtures+Corpus.swift; ContentCorpusSamples only reads the vector's data into HealthKit types. New tests cover restated(_:facts:), electrocardiogram(facts:reading:), voltageMeasurement and every corpus builder, and the undeclared-key refusal. - StoredElectrocardiogram.state(_:) is fileprivate and attaches the reading without an NSObject box; SeriesShape is SampleFacts (it carries any stored sample's facts), GoldenCase.seriesShape is seriesFacts. - The reverse projection renders a quantity in the unit the Observation states (the unit the projection created it in) instead of reading HKQuantity's private unit. Shared tooling (C2, C4, C9, B6, B13): - CheckedInResources holds the bundle lookup, missing-file error and regeneration directory of the goldens and the corpus, and refuses a regeneration directory inside the checkout. Each family has its own variable: GROVE_GOLDEN_OUTPUT_DIR (goldens) and the new GROVE_CONTENT_CORPUS_OUTPUT_DIR (corpus, TEST_RUNNER_ prefix under xcodebuild), so regenerating the goldens no longer skips the corpus. - TokenDiff.swift (with the LosslessJSONValue accessors and canonicalText) is shared and reports every difference, not only the first. - corpusRegenerates compares the regeneration with the checked-in corpus and writes content-corpus.changes.txt beside it (added, removed and duplicated ids, restated inputs and changed outputs, each difference with both values in full). It writes nothing when a vector converts nondeterministically (#require), or when an id is dropped, duplicated or has its input restated, unless GROVE_CONTENT_CORPUS_ALLOW_RESTATED_INPUTS names the id prefixes a schema change restates. - everyLineIsReproduced also compares each re-printed line with the checked-in bytes, which catches what token equality cannot (canonically equivalent strings). - No try? when reading lines; gridIsTheCheckedInCorpus reports the stray, missing, misordered and restated ids instead of both arrays. - .gitattributes marks content-corpus.jsonl linguist-generated. Grid and invariants (C3, C7, B11, C10-C14): - The grid is the same on every platform; only the clinical builder knows watchOS has no clinical records (RebuildError.unavailableHere), the reproduction skips exactly those vectors, and the regeneration refuses to run on watchOS. - The grid doc no longer promises appended, never renumbered vectors; it states the append-only id rule ContentCorpusChanges enforces. The unit spellings are frozen as a list, and the body-mass-index vectors keep their recorded inputs whatever M1 generates. What M1 must do is documented there: if generator G3 adds the BMI contract to MeasurementCatalog.all or HealthKitMeasurementCatalog.all, reverse/body-mass-index stops being refused (an output change to enumerate or avoid) and ContentInvariantTests.quantityUnitsAreCompatible counts 108 rows, not 107. - The O6 cataloged-output check mints with HealthKitConverter.adapterID under the context the vector converted in. Inputs lose their unused Hashable conformances; dead imports and a never-running merge closure are gone; the deprecated HealthKitConverter calls are marked as port points; the input schema is documented field by field. - The golden ECG, heartbeat and route cases state the corpus's reading, beats and fixes instead of copies, and their comment says why they still use the convertECG seam. Output: unchanged. Regenerating with this commit's code reproduces the checked-in corpus byte for byte (the change report: 0 added, 0 removed, 0 restated, 0 changed). Gate 1 (macOS): 282 tests, 279 passed, 0 failed, 3 skipped (corpus regeneration and the two benchmark tests); all 42 goldens and outlines.json pass. SwiftLint strict and reuse lint clean. Rebased onto 28f93119 (exchange-ledger fix round): GoldenStore keeps that round's internal access, as its GoldenOutputRevisionTests reads it, and that suite now lists the checked-in goldens through GoldenStore.resources like GoldenGraphTests does. The round's ECG golden helper electrocardiogramEvidence(uuid:symptomsPresent:) states the corpus reading, and its exporter record tests take GoldenCase.seriesFacts like every other caller. Rebased onto 48911aa0 (the exchange-ledger fix round's G3 and G1b), tests only: that round's fixture additions follow the key table. withMetadata restates metadata through restate(_:with:); its own clinical-record and ECG fixtures give way to clinicalRecord(_:fhirVersion:resource:facts:) and electrocardiogram(facts:reading:), which the clinical exporter goldens and sourceEvidenceReadsTheSample now build on (the conversion reads a clinical record's data and release only, so those goldens are unchanged). The round's TokenDiff changes (a member name that differs only in its Unicode scalars, non-ASCII scalars printed as \u{...}) move into TokenDiff.swift, its rule that a golden regeneration run fails moves onto CheckedInResources, and its ECG evidence fixture keeps averageHeartRate and timeZoned while stating the corpus reading. Co-Authored-By: Claude Opus 5.5 --- .gitattributes | 11 + .../CheckedInResources.swift | 122 ++++++++ .../ContentCorpus/ContentCorpusCatalog.swift | 9 +- .../ContentCorpus/ContentCorpusChanges.swift | 128 ++++++++ .../ContentCorpusGrid+Catalog.swift | 39 +-- .../ContentCorpusGrid+Clinical.swift | 14 +- .../ContentCorpus/ContentCorpusGrid.swift | 27 +- .../ContentCorpus/ContentCorpusInput.swift | 85 +++++- .../ContentCorpusRecorder+Projections.swift | 108 +++++++ .../ContentCorpus/ContentCorpusRecorder.swift | 121 ++------ .../ContentCorpusSamples+Recordings.swift | 104 +++++++ .../ContentCorpusSamples+Records.swift | 252 ---------------- .../ContentCorpus/ContentCorpusSamples.swift | 190 ++++++------ .../ContentCorpus/ContentCorpusStore.swift | 161 +++++----- .../ContentCorpus/ContentCorpusTests.swift | 84 ++++-- .../ContentCorpus/ContentInvariantTests.swift | 29 +- .../ExchangeEnvelopeFixTests.swift | 8 +- .../ExporterCompanionFingerprintTests.swift | 4 +- .../GoldenGraphCases+Documents.swift | 71 ++--- .../GoldenGraphCases+Exporter.swift | 8 +- .../GoldenGraphTests.swift | 127 ++------ .../GoldenOutputRevisionTests.swift | 2 +- .../HealthKitECGEvidenceValidatorTests.swift | 17 +- .../HealthKitFHIRExporterRecordTests.swift | 6 +- .../HealthKitFHIRExporterTests.swift | 2 +- .../StoredSampleFixtures+Corpus.swift | 272 +++++++++++++++++ .../StoredSampleFixtures.swift | 279 ++++++++---------- .../StoredSampleFixturesTests.swift | 108 ++++++- Tests/GroveHealthKitFHIRTests/TokenDiff.swift | 211 +++++++++++++ 29 files changed, 1630 insertions(+), 969 deletions(-) create mode 100644 .gitattributes create mode 100644 Tests/GroveHealthKitFHIRTests/CheckedInResources.swift create mode 100644 Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusChanges.swift create mode 100644 Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusRecorder+Projections.swift create mode 100644 Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusSamples+Recordings.swift delete mode 100644 Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusSamples+Records.swift create mode 100644 Tests/GroveHealthKitFHIRTests/StoredSampleFixtures+Corpus.swift create mode 100644 Tests/GroveHealthKitFHIRTests/TokenDiff.swift diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..7c3db29cd --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +# +# This source file is part of the Grove open-source project +# +# SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +# +# SPDX-License-Identifier: MIT +# + +# The HealthKit content corpus is recorded by its tests (see ContentCorpusStore): review a regeneration through the +# content-corpus.changes.txt it writes beside the corpus, not through this file's one-line-per-vector diff. +Tests/GroveHealthKitFHIRTests/Resources/ContentCorpus/content-corpus.jsonl linguist-generated=true diff --git a/Tests/GroveHealthKitFHIRTests/CheckedInResources.swift b/Tests/GroveHealthKitFHIRTests/CheckedInResources.swift new file mode 100644 index 000000000..b958f1db6 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/CheckedInResources.swift @@ -0,0 +1,122 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation + + +/// A family of checked-in test resources, and where a run regenerates it. +/// +/// A family regenerates OUTSIDE the checkout: its environment variable (under `xcodebuild`, prefixed with +/// `TEST_RUNNER_`) names a directory the run writes into, and the files are copied into `Resources/` afterwards. +/// Writing into the checkout while Xcode runs the tests makes it re-resolve the package graph mid-run, so a +/// directory inside the checkout is refused. Each family has its own variable, so regenerating one never +/// regenerates, or stops verifying, another. +struct CheckedInResources: Sendable { + /// No file of the family is checked in under the name a test asked for. + struct Missing: Error, CustomStringConvertible { + /// The file the test looked for. + let file: String + /// The family it belongs to. + let family: CheckedInResources + + var description: String { + "No \(file) is checked in; regenerate with \(family.environmentVariable) and copy it into Resources/\(family.subdirectory)" + } + } + + /// The regeneration directory lies inside the checkout the tests were built from. + struct OutputInsideCheckout: Error, CustomStringConvertible { + /// The directory the environment named. + let directory: URL + + var description: String { + "\(directory.path) lies inside the checkout; regenerate into a directory outside it and copy the files in afterwards" + } + } + + /// The goldens: one sorted-member graph per case and `outlines.json`. + static let goldens = CheckedInResources(subdirectory: "Goldens", environmentVariable: "GROVE_GOLDEN_OUTPUT_DIR") + /// The content corpus and, on regeneration, its change report. + static let contentCorpus = CheckedInResources(subdirectory: "ContentCorpus", environmentVariable: "GROVE_CONTENT_CORPUS_OUTPUT_DIR") + + /// The checkout this test target was compiled from: the nearest directory above this file with a `Package.swift`, + /// or nil when the sources are not on this machine (a regeneration directory cannot lie inside them then). + private static let checkout: URL? = { + var directory = URL(fileURLWithPath: #filePath).deletingLastPathComponent() + while directory.pathComponents.count > 1 { + if FileManager.default.fileExists(atPath: directory.appendingPathComponent("Package.swift").path) { + return directory + } + directory.deleteLastPathComponent() + } + return nil + }() + + /// The subdirectory of `Resources/` the family is checked in under. + let subdirectory: String + /// The environment variable naming the regeneration directory. + let environmentVariable: String + + /// The regeneration directory the environment names, or nil when this run verifies. + var outputDirectory: URL? { + ProcessInfo.processInfo.environment[environmentVariable] + .flatMap { $0.isEmpty ? nil : URL(fileURLWithPath: $0, isDirectory: true) } + } + + /// Whether this run regenerates the family instead of verifying it. + var isGenerating: Bool { + outputDirectory != nil + } + + /// The path components of `url` with every symbolic link in its longest existing prefix resolved, so + /// `/tmp/x` and `/private/tmp/x` compare alike whether or not `x` exists yet. + private static func resolvedComponents(_ url: URL) -> [String] { + var existing = url.standardizedFileURL + var missing: [String] = [] + while !FileManager.default.fileExists(atPath: existing.path), existing.pathComponents.count > 1 { + missing.insert(existing.lastPathComponent, at: 0) + existing.deleteLastPathComponent() + } + return existing.resolvingSymlinksInPath().pathComponents + missing + } + + /// Every checked-in file of the family with `fileExtension`, by name, whichever way the build system laid the + /// resources out: `.process` flattens the subdirectory, and a lookup under a subdirectory that is not there + /// answers an empty array, not nil. + func names(withExtension fileExtension: String) -> Set { + let urls = [subdirectory, nil] + .compactMap { Bundle.module.urls(forResourcesWithExtension: fileExtension, subdirectory: $0) } + .first { !$0.isEmpty } ?? [] + return Set(urls.map { $0.deletingPathExtension().lastPathComponent }) + } + + /// The bytes of one checked-in file of the family. + func data(named name: String, withExtension fileExtension: String) throws -> Data { + guard let url = Bundle.module.url(forResource: name, withExtension: fileExtension, subdirectory: subdirectory) + ?? Bundle.module.url(forResource: name, withExtension: fileExtension) else { + throw Missing(file: "\(name).\(fileExtension)", family: self) + } + return try Data(contentsOf: url) + } + + /// Writes one regenerated file into the regeneration directory, which must lie outside the checkout. + func write(_ data: Data, toFile file: String) throws { + guard let directory = outputDirectory else { + return + } + if let checkout = Self.checkout, Self.resolvedComponents(directory).starts(with: Self.resolvedComponents(checkout)) { + throw OutputInsideCheckout(directory: directory) + } + try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true) + try data.write(to: directory.appendingPathComponent(file)) + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusCatalog.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusCatalog.swift index 2353dd3f4..e52211eb6 100644 --- a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusCatalog.swift +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusCatalog.swift @@ -16,8 +16,9 @@ import ModelsR4 /// Renders the public catalog surface the content layer publishes: inventory rows with their outputs and field -/// dispositions, the unit bindings and both unit lookups, and the reverse projection of Observations. +/// dispositions, the unit bindings, both unit lookups, and the reverse projection of Observations. enum ContentCorpusCatalog { + /// The tokens one catalog projection renders as. static func projection(_ projection: ContentCorpusProjection) throws -> LosslessJSONValue { switch projection { case .entry(let type): @@ -31,12 +32,12 @@ enum ContentCorpusCatalog { ]) }) case .unitSpellings(let spellings): - .object(Dictionary(spellings.map { spelling in + .object(Dictionary(uniqueKeysWithValues: spellings.map { spelling in (spelling, LosslessJSONValue.object([ "ucumCode": unitText(HealthKitCatalog.unit(forUCUMCode: spelling)), "unitSpelling": unitText(HealthKitCatalog.unit(forUnitSpelling: spelling)) ])) - }) { first, _ in first }) + })) case .reverse(let observation): ContentCorpusRecorder.reverse(try JSONDecoder().decode(Observation.self, from: Data(observation.utf8))) } @@ -67,10 +68,12 @@ enum ContentCorpusCatalog { ]) } + /// A unit as its unit string, or null when the lookup found none. private static func unitText(_ unit: HKUnit?) -> LosslessJSONValue { unit.map { .string($0.unitString) } ?? .null } + /// A canonical as `url|version`, or its url alone. private static func canonicalText(_ canonical: FHIRPrimitive) -> String { guard let value = canonical.value else { return "" diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusChanges.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusChanges.swift new file mode 100644 index 000000000..01fe6d773 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusChanges.swift @@ -0,0 +1,128 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +@testable import GroveFHIRContract + + +/// How a regenerated corpus differs from the checked-in one, line by line and token by token, read without the +/// input schema so a corpus written by any version compares. +/// +/// Ids are append-only: an id names one input for as long as the corpus exists, so a regeneration may add +/// vectors but never drops an id, names two lines alike, or restates an existing id's input (`corpusRegenerates` +/// refuses to write such a corpus). Only a commit that changes how inputs are stated, and enumerates every +/// restated id, sets `GROVE_CONTENT_CORPUS_ALLOW_RESTATED_INPUTS` (under `xcodebuild`, with the `TEST_RUNNER_` +/// prefix) to the comma-separated id prefixes whose inputs it restates. +struct ContentCorpusChanges { + /// One line read as tokens. + private struct Tokens { + /// The line's input. + let input: LosslessJSONValue + /// The line's output. + let output: LosslessJSONValue + } + + /// The environment variable that admits restated inputs for one regeneration. + static let allowRestatedInputs = "GROVE_CONTENT_CORPUS_ALLOW_RESTATED_INPUTS" + + /// The id prefixes whose inputs this regeneration may restate. + static var restatablePrefixes: [String] { + (ProcessInfo.processInfo.environment[allowRestatedInputs] ?? "").split(separator: ",").map(String.init).filter { !$0.isEmpty } + } + + /// Ids the regeneration adds, in corpus order. + private(set) var added: [String] = [] + /// Ids the checked-in corpus has and the regeneration lacks. + private(set) var removed: [String] = [] + /// Ids whose input differs, with every differing path. + private(set) var restated: [String] = [] + /// Ids whose output differs, with every differing path. + private(set) var changed: [String] = [] + /// Ids the regeneration names on more than one line. + private(set) var duplicated: [String] = [] + /// Every difference, one line each: `restated|changed : -> `. + private(set) var differences: [String] = [] + /// How many lines were checked in. + private(set) var checkedInCount = 0 + + /// The report `content-corpus.changes.txt` states: a summary, then every added and removed id and every + /// difference with both values in full. + var report: String { + let summary = [ + "content-corpus changes: \(checkedInCount) lines checked in", + "added \(added.count), removed \(removed.count), duplicated \(duplicated.count), restated inputs \(restated.count), changed outputs \(changed.count)", + "" + ] + return (summary + added.map { "added \($0)" } + removed.map { "removed \($0)" } + duplicated.map { "duplicated \($0)" } + differences) + .map { $0 + "\n" } + .joined() + } + + /// The restated ids no allowed prefix covers. + var unallowedRestatements: [String] { + let prefixes = Self.restatablePrefixes + return restated.filter { id in !prefixes.contains { id.hasPrefix($0) } } + } + + /// Compares the regenerated lines with the checked-in corpus. + init(checkedIn: Data, regenerated: [String]) throws { + var old: [String: Tokens] = [:] + var oldOrder: [String] = [] + for (number, bytes) in ContentCorpusStore.rawLines(checkedIn) { + let (id, tokens) = try Self.tokens(of: bytes, number: number) + old[id] = tokens + oldOrder.append(id) + } + checkedInCount = oldOrder.count + var seen: Set = [] + for (index, line) in regenerated.enumerated() { + let (id, new) = try Self.tokens(of: Data(line.utf8), number: index + 1) + guard seen.insert(id).inserted else { + duplicated.append(id) + continue + } + guard let previous = old[id] else { + added.append(id) + continue + } + let restatement = Self.lines(TokenDiff.differences(expected: previous.input, actual: new.input), of: id, as: "restated") + let change = Self.lines(TokenDiff.differences(expected: previous.output, actual: new.output), of: id, as: "changed") + if !restatement.isEmpty { + restated.append(id) + } + if !change.isEmpty { + changed.append(id) + } + differences += restatement + change + } + removed = oldOrder.filter { !seen.contains($0) } + } + + /// A line's id and its input and output tokens. + private static func tokens(of bytes: Data, number: Int) throws -> (String, Tokens) { + let line: LosslessJSONValue + do { + line = try LosslessJSONValue(parsing: bytes) + } catch { + throw ContentCorpusStore.MalformedLine(number: number, reason: String(describing: error)) + } + guard let id = line["id"]?.text, let input = line["input"], let output = line["output"] else { + throw ContentCorpusStore.MalformedLine(number: number, reason: "no id, input or output") + } + return (id, Tokens(input: input, output: output)) + } + + /// One report line per difference of `id`'s input or output. + private static func lines(_ found: [TokenDiff.Difference], of id: String, as kind: String) -> [String] { + found.map { "\(kind) \(id) \($0.change)" } + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Catalog.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Catalog.swift index 83c5104a1..10277470e 100644 --- a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Catalog.swift +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Catalog.swift @@ -14,17 +14,17 @@ import Foundation import HealthKit -/// Clinical documents, retractions, the catalog projections and reverse projections. +/// Retractions, the catalog projections and reverse projections. extension ContentCorpusGrid { - /// CDA documents and clinical records: every type and admitted release, refused releases and payloads, - /// missing payloads, bytes kept as delivered, and every link. watchOS has neither. - static var clinicalDocuments: [ContentCorpusVector] { - #if os(watchOS) - [] - #else - cdaDocuments + clinicalRecords - #endif - } + /// The spellings both unit lookups are asked for: every UCUM code and display unit the bindings used when the + /// corpus was recorded, and spellings they do not use. Frozen, since the bindings are what the rewrite rewires; + /// `catalog/unit-bindings` pins the bindings themselves. + static let unitSpellings = [ + "", "%", "/h", "/min", "Cel", "IU", "L", "L/min", "UV index", "W", "[iU]", "beats/minute", "breaths/minute", "cm", "dB(SPL)", + "dB[SPL]", "drinks", "falls", "flights", "g", "kcal", "kcal/(kg.h)", "kcal/kg/h", "kg", "kg/m2", "m", "m/s", "mL", "mL/kg/min", + "mg", "mg/dL", "min", "mmHg", "mm[Hg]", "ms", "not-a-unit", "puffs", "pushes", "revolutions/minute", "score", "steps", "strokes", + "uS", "ug", "{drinks}", "{falls}", "{flights}", "{puff}", "{pushes}", "{score}", "{steps}", "{strokes}", "{uvindex}" + ] /// The deletion of a record of every inventory row. static var retractions: [ContentCorpusVector] { @@ -34,28 +34,29 @@ extension ContentCorpusGrid { } /// Every inventory row with its outputs and field dispositions, the unit bindings, and both unit lookups for - /// every spelling the bindings use plus spellings they do not. + /// every spelling. static var catalog: [ContentCorpusVector] { let entries = HealthKitContract.rows.map { row in ContentCorpusVector(id: "catalog/entry/\(row.sourceTypeIdentifier)", input: .catalog(projection: .entry(type: row.sourceTypeIdentifier))) } - let spellings = Set(HealthKitCatalog.unitBindings.flatMap { [$0.ucumCode, $0.displayUnit] }) - .union(["", "%", "/h", "Cel", "kg", "kg/m2", "mmHg", "mm[Hg]", "beats/minute", "not-a-unit"]) - .sorted() return entries + [ ContentCorpusVector(id: "catalog/unit-bindings", input: .catalog(projection: .unitBindings)), - ContentCorpusVector(id: "catalog/unit-spellings", input: .catalog(projection: .unitSpellings(spellings: spellings))) + ContentCorpusVector(id: "catalog/unit-spellings", input: .catalog(projection: .unitSpellings(spellings: unitSpellings))) ] } /// A minimal Observation of every generated measurement and of body-mass index, and the edges of the /// reverse projection: Period and missing effective times, missing and mismatched values, manual entry, /// zones, a pre-1582 date, sync identity and amendment, and blood-pressure components. + /// + /// Body-mass index keeps the literal Observation it was recorded with, whether or not a catalog generates its + /// contract, and every other measurement appears once, the first catalog winning. static var reverseProjections: [ContentCorpusVector] { - var observations = (MeasurementCatalog.all + HealthKitMeasurementCatalog.all).map { contract in - (contract.id, minimalObservation(contract)) + var seen: Set = [bodyMassIndexID] + var observations = (MeasurementCatalog.all + HealthKitMeasurementCatalog.all).compactMap { contract in + seen.insert(contract.id).inserted ? (contract.id, minimalObservation(contract)) : nil } - observations.append(("body-mass-index", observation(code: ("http://loinc.org", "39156-5"), quantity: quantity("kg/m2", unit: "kg/m2", value: 1)))) + observations.append((bodyMassIndexID, observation(code: ("http://loinc.org", "39156-5"), quantity: quantity("kg/m2", unit: "kg/m2", value: 1)))) let projected = observations.map { id, resource in ContentCorpusVector(id: "reverse/\(id)", input: .catalog(projection: .reverse(observation: json(resource)))) } @@ -133,6 +134,7 @@ extension ContentCorpusGrid { return NSDecimalNumber(decimal: rounded).doubleValue } + /// A final Observation of `code` at the base instant in Los Angeles, stating `quantity`. static func observation(code: (system: String, code: String), quantity: [String: Any]) -> [String: Any] { [ "resourceType": "Observation", @@ -143,6 +145,7 @@ extension ContentCorpusGrid { ] } + /// A `valueQuantity` of `value` in UCUM `code`, displayed as `unit`. static func quantity(_ code: String, unit: String, value: Double, system: String = "http://unitsofmeasure.org") -> [String: Any] { ["system": system, "code": code, "unit": unit, "value": value] } diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Clinical.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Clinical.swift index 3bc8bd1a0..a266c7338 100644 --- a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Clinical.swift +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Clinical.swift @@ -6,18 +6,25 @@ // SPDX-License-Identifier: MIT // -#if canImport(HealthKit) && !os(watchOS) +#if canImport(HealthKit) import Foundation import GroveFHIRContract import HealthKit -/// CDA documents and clinical records, which watchOS does not have. +/// CDA documents and clinical records. The vectors are data on every platform; watchOS, which has neither, +/// skips them when it rebuilds the records. extension ContentCorpusGrid { /// A provider's R4 resource, carried byte for byte. static let clinicalResource = #"{"resourceType":"Observation","id":"r4"}"# + /// CDA documents and clinical records: every type and admitted release, refused releases and payloads, + /// missing payloads, bytes kept as delivered, and every link. + static var clinicalDocuments: [ContentCorpusVector] { + cdaDocuments + clinicalRecords + } + /// The goldens' CDA document, then a blank and a padded title, an empty document and none at all, and every link. static var cdaDocuments: [ContentCorpusVector] { func document(_ label: String, title: String, document: String?) -> ContentCorpusVector { @@ -41,7 +48,7 @@ extension ContentCorpusGrid { /// Every clinical type in R4, then DSTU2, an unknown release, payloads the guides refuse, a missing resource, /// bytes kept with their whitespace, every link, and which refusal comes first. static var clinicalRecords: [ContentCorpusVector] { - let labResult = HKClinicalTypeIdentifier.labResultRecord.rawValue + let labResult = "HKClinicalTypeIdentifierLabResultRecord" func record(_ label: String, type: String = labResult, version: String = "4.0.1", resource: String? = clinicalResource) -> ContentCorpusVector { convert("clinical/\(label)", ContentCorpusSource(.clinicalRecord(type: type, fhirVersion: version, resource: resource), end: start)) } @@ -56,6 +63,7 @@ extension ContentCorpusGrid { record("unknown-release", version: "3.0.1"), record("undecodable/duplicate-member", resource: duplicateMember), record("undecodable/lowercase-type", resource: #"{"resourceType":"observation"}"#), + // The payload starts with a byte order mark (U+FEFF), which the corpus prints escaped. record("undecodable/byte-order-mark", resource: "\u{FEFF}" + clinicalResource), record("undecodable/array", resource: "[]"), record("no-resource", resource: nil), diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid.swift index 0ac53fe09..8e837bad6 100644 --- a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid.swift +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid.swift @@ -14,15 +14,25 @@ import GroveFHIRContract import HealthKit -/// Every content-corpus vector, generated from the public catalog alone: the input coverage of the step-7 oracle -/// (synthesis section 16, O2), in a fixed order, each under a stable id. +/// Every content-corpus vector, generated from the public catalog and the generated contracts: the input coverage +/// of the step-7 oracle (synthesis section 16, O2), in a fixed order, each under a stable id. The grid is the same +/// on every platform; a platform without a record type skips its vectors when it rebuilds them. /// /// Families: every quantity type over a value sweep (and every percent type over fractions), every category type /// over raw values -1 through 8, effective-time edges for each effective kind, blood-pressure member variants, /// every workout activity raw with and without statistics, State of Mind permutations, scored assessments, each /// metadata key valid, wrongly typed and absent, ECG evidence edges, every recording and clinical document -/// builder, multi-fault precedence, retraction targets, and the catalog projections. Vectors are appended, never -/// renumbered: an id names the same input for as long as the corpus exists. +/// builder, multi-fault precedence, retraction targets, and the catalog projections. +/// +/// Ids are stable: an id names one input for as long as the corpus exists. A regeneration may add vectors (each +/// inside its family, so later lines move) but never drops an id or restates its input; `ContentCorpusChanges` +/// enforces both. Inputs derived from what the rewrite regenerates are frozen here: the unit spellings are listed, +/// and the body-mass-index vectors keep the inputs they were recorded with. M1 (generator G3) generates a BMI +/// contract; `contracts` and the reverse projections skip a generated `body-mass-index`, so +/// `quantity/HKQuantityTypeIdentifierBodyMassIndex/...` keep their fallback unit and value and `reverse/body-mass-index` +/// keeps its literal Observation. Should G3 add the contract to `MeasurementCatalog.all` or +/// `HealthKitMeasurementCatalog.all`, `reverse/body-mass-index` stops being refused (an output change M1 has to +/// enumerate or avoid) and `ContentInvariantTests.quantityUnitsAreCompatible` counts 108 unit-bound rows, not 107. enum ContentCorpusGrid { /// 2026-08-17T22:30:00Z, 15:30 in Los Angeles: when every vector's record starts unless it states otherwise. static let start = GoldenFixtures.sampleStart.timeIntervalSince1970 @@ -42,11 +52,15 @@ enum ContentCorpusGrid { .gramUnit(with: .milli).unitDivided(by: .literUnit(with: .deci)), .literUnit(with: .milli).unitDivided(by: .minute()) ] - /// Every generated measurement contract by id; the first catalog wins, as everywhere else. + /// Every generated measurement contract by id, the first catalog winning, as everywhere else; a generated + /// body-mass-index contract is skipped, so the BMI vectors keep the inputs they were recorded with. static let contracts: [String: MeasurementContract] = Dictionary( - (MeasurementCatalog.all + HealthKitMeasurementCatalog.all).map { ($0.id, $0) } + (MeasurementCatalog.all + HealthKitMeasurementCatalog.all).filter { $0.id != bodyMassIndexID }.map { ($0.id, $0) } ) { first, _ in first } + /// The measurement id of body-mass index, whose contract no generated catalog carried when the corpus was recorded. + static let bodyMassIndexID = "body-mass-index" + /// Every vector, in corpus order. static var vectors: [ContentCorpusVector] { quantities + categories + times + correlations + workouts + statesOfMind + assessments + bareRows @@ -142,6 +156,7 @@ enum ContentCorpusGrid { ("year-1", -62_135_596_800), ("year-0", -62_135_596_801) ] + /// The vector converting `source`, under `id`. static func convert(_ id: String, _ source: ContentCorpusSource) -> ContentCorpusVector { ContentCorpusVector(id: id, input: .convert(source: source)) } diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusInput.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusInput.swift index f3f2705da..2350acfd5 100644 --- a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusInput.swift +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusInput.swift @@ -10,16 +10,25 @@ import Foundation +// The input schema of `content-corpus.jsonl`: every type here is Codable as the corpus prints it, and every field +// is documented as the data it states. Inputs compare by their printed text (`ContentCorpusStore.inputText`), so +// no type is Hashable, which a NaN reading would make irreflexive. + /// One metadata value as HealthKit stores it: a string, an integer or floating-point number, or a Boolean. /// /// Encoded as a one-member object naming its kind, so `1`, `1.0` and `true` stay three different inputs. -enum ContentCorpusMetadataValue: Codable, Hashable, Sendable { +enum ContentCorpusMetadataValue: Codable, Sendable { + /// A string, as `NSString` stores it. case string(String) + /// An integer, as `NSNumber` stores it. case integer(Int) + /// A floating-point number, as `NSNumber` stores it. case double(Double) + /// A Boolean, as `NSNumber` stores it. case boolean(Bool) + /// The member naming the value's kind. private enum CodingKeys: String, CodingKey { case string case integer @@ -53,46 +62,69 @@ enum ContentCorpusMetadataValue: Codable, Hashable, Sendable { /// One member of a correlation: its quantity type, value in `unit`, and the metadata it states itself. -struct ContentCorpusMember: Codable, Hashable, Sendable { +struct ContentCorpusMember: Codable, Sendable { + /// The member's quantity type identifier. var type: String + /// The member's reading, in `unit`. var value: Double + /// The unit the reading is stated in, as `HKUnit(from:)` parses it. var unit = "mmHg" + /// The metadata the member states itself, apart from the correlation's. var metadata: [String: ContentCorpusMetadataValue] = [:] } /// One workout statistic, each reading in `unit`; an absent reading is one HealthKit did not report. -struct ContentCorpusStatistic: Codable, Hashable, Sendable { +struct ContentCorpusStatistic: Codable, Sendable { + /// The statistic's quantity type identifier. var type: String + /// The unit every reading is stated in, as `HKUnit(from:)` parses it. var unit: String + /// The cumulative reading. var sum: Double? + /// The average reading. var average: Double? + /// The smallest reading. var minimum: Double? + /// The largest reading. var maximum: Double? } /// An ECG's reading, voltages and correlated symptoms, as raw as HealthKit reports them. -struct ContentCorpusElectrocardiogram: Codable, Hashable, Sendable { +struct ContentCorpusElectrocardiogram: Codable, Sendable { /// One voltage measurement; a nil voltage states no lead at all. - struct Voltage: Codable, Hashable, Sendable { + struct Voltage: Codable, Sendable { + /// Seconds since the ECG's start. var offset: Double + /// The lead's voltage in millivolts. var millivolts: Double? } - /// One correlated symptom sample, with its own UUID ordinal and the event context it converts under. - struct Symptom: Codable, Hashable, Sendable { + /// One correlated symptom sample: a category type, its raw value, and the last byte of its UUID. It converts + /// under the event after the ECG's and those of the symptoms before it. + struct Symptom: Codable, Sendable { + /// The symptom's category type identifier. var type: String + /// The symptom's raw category value. var value: Int + /// The last byte of the symptom's UUID (`GoldenFixtures.uuid(_:)`). var ordinal: UInt8 } + /// The raw `HKElectrocardiogram.Classification`. var classification: Int + /// The raw `HKElectrocardiogram.SymptomsStatus`. var symptomsStatus: Int + /// How many voltages HealthKit reports the recording to have. var reportedCount: Int + /// The average heart rate in beats per minute. var averageHeartRate: Double? + /// The sampling frequency in hertz. var samplingFrequency: Double? + /// The lead's voltages in the order HealthKit delivers them. var voltages: [Voltage] + /// The symptom samples correlated with the ECG, in the record's order. var symptoms: [Symptom] = [] /// How many symptom contexts the caller supplies, when that is not one per symptom. var symptomContexts: Int? @@ -100,38 +132,56 @@ struct ContentCorpusElectrocardiogram: Codable, Hashable, Sendable { /// One heartbeat of a series: seconds since the series start, and whether a gap preceded it. -struct ContentCorpusBeat: Codable, Hashable, Sendable { +struct ContentCorpusBeat: Codable, Sendable { + /// Seconds since the series start. var offset: Double + /// Whether the recording paused before this beat. var gap: Bool } /// One route fix, `offset` seconds after the route starts; CoreLocation reports an unavailable reading as negative. -struct ContentCorpusLocation: Codable, Hashable, Sendable { +struct ContentCorpusLocation: Codable, Sendable { + /// Seconds since the route's start. var offset: Double + /// Degrees north. var latitude: Double + /// Degrees east. var longitude: Double + /// Meters above sea level. var altitude: Double + /// Meters; negative when unavailable. var horizontalAccuracy: Double + /// Meters; negative when unavailable. var verticalAccuracy: Double + /// Degrees from true north; negative when unavailable. var course: Double + /// Degrees; negative when unavailable. var courseAccuracy: Double + /// Meters per second; negative when unavailable. var speed: Double + /// Meters per second; negative when unavailable. var speedAccuracy: Double } /// The payload of one source record, by the HealthKit class that carries it. -enum ContentCorpusRecord: Codable, Hashable, Sendable { +enum ContentCorpusRecord: Codable, Sendable { + /// A quantity sample of `value` in `unit` (as `HKUnit(from:)` parses it). case quantity(type: String, value: Double, unit: String) /// A category sample with any raw value, admitted by HealthKit or not. case category(type: String, value: Int) + /// A correlation of exactly `members`. case correlation(type: String, members: [ContentCorpusMember]) + /// A workout of any raw activity type, `duration` seconds long, with `statistics` in its primary activity. case workout(activity: UInt, duration: Double, statistics: [ContentCorpusStatistic]) + /// A reflection of any raw kind, labels and associations. case stateOfMind(kind: Int, valence: Double, labels: [Int], associations: [Int]) + /// A GAD-7 or PHQ-9 assessment stating any score. case assessment(type: String, score: Int) /// An ECG with its companion data, converted through the record entry point. case electrocardiogram(reading: ContentCorpusElectrocardiogram) + /// A heartbeat series with its beats. case heartbeatSeries(beats: [ContentCorpusBeat]) /// A route with its fixes; `disclosed` is the route-disclosure policy. case workoutRoute(locations: [ContentCorpusLocation], disclosed: Bool) @@ -145,7 +195,7 @@ enum ContentCorpusRecord: Codable, Hashable, Sendable { /// One source record and the facts its sample carries besides its payload. -struct ContentCorpusSource: Codable, Hashable, Sendable { +struct ContentCorpusSource: Codable, Sendable { /// The `HKDevice` the sample names. enum Device: String, Codable, Sendable { /// A watch with a per-unit token, so the graph carries a recording Device. @@ -170,20 +220,25 @@ struct ContentCorpusSource: Codable, Hashable, Sendable { case linked } + /// The record's payload. var record: ContentCorpusRecord /// The sample's start, in seconds since 1970. var start: Double /// The sample's end, in seconds since 1970. var end: Double + /// The sample's metadata. var metadata: [String: ContentCorpusMetadataValue] + /// The device the sample names, if any. var device: Device? + /// The writer the sample is attributed to. var writer: Writer + /// The event context the record converts under. var context: Context } /// One part of the public catalog surface. -enum ContentCorpusProjection: Codable, Hashable, Sendable { +enum ContentCorpusProjection: Codable, Sendable { /// A source type's inventory row, outputs and field dispositions. case entry(type: String) /// Every published unit binding, in order. @@ -196,15 +251,17 @@ enum ContentCorpusProjection: Codable, Hashable, Sendable { /// One corpus line's key and input. -struct ContentCorpusVector: Hashable, Sendable { +struct ContentCorpusVector: Sendable { + /// The line's stable key. let id: String + /// What the line feeds the converter. let input: ContentCorpusInput } /// What one content-corpus vector feeds the converter, stated as data so the corpus rebuilds every record /// from the checked-in file alone, through `StoredSampleFixtures`, whatever code produced the line. -enum ContentCorpusInput: Codable, Hashable, Sendable { +enum ContentCorpusInput: Codable, Sendable { /// Convert one source record. case convert(source: ContentCorpusSource) /// Name the outputs a deletion of a record of this type retracts. diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusRecorder+Projections.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusRecorder+Projections.swift new file mode 100644 index 000000000..e719d0344 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusRecorder+Projections.swift @@ -0,0 +1,108 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +@testable import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit +import ModelsR4 + + +/// The retractions and the reverse projection: the targets a deletion names, and the sample an Observation +/// projects back to. +extension ContentCorpusRecorder { + /// The sample `observation` projects back to, or why it does not. + static func reverse(_ observation: Observation) -> LosslessJSONValue { + do { + return sample(try observation.healthKitSample(), units: statedUnits(of: observation)) + } catch { + let refusal = LosslessJSONValue.object([ + "code": .string(error.diagnostic.code), + "error": .string(String(describing: error)) + ]) + return .object(["refused": refusal]) + } + } + + /// The deletion of a record of `type`: the targets it retracts, or why it retracts none. + static func retraction(of type: String) throws -> LosslessJSONValue { + guard let sourceType = HealthKitSourceType(rawValue: type) else { + throw ContentCorpusSamples.RebuildError.unknownType(type) + } + let context = try GoldenFixtures.context(sequence: sequence) + let record = HealthKitSourceRecord(uuid: ContentCorpusSamples.uuid, type: sourceType) + do { + let targets = try HealthKitConverter().retractionTargets(for: record, context: context) // Port point: the deprecated facade. + return .object(["targets": .array(targets.map(target))]) + } catch { + return refusal(error) + } + } + + /// One retraction target: its identifier and role, and the resource type and role it retracts. + private static func target(_ target: RetractionTarget) -> LosslessJSONValue { + .object([ + "identifier": .string(target.identifier.identifier.value), + "identifierRole": .string(target.identifier.role.rawValue), + "resourceType": .string(target.resourceType.rawValue), + "role": .string(target.role.rawValue) + ]) + } + + /// A projected sample's type, interval, metadata, value and members, every number as its shortest text. + private static func sample(_ sample: HKSample, units: [HKUnit]) -> LosslessJSONValue { + let metadata = sample.metadata ?? [:] + var members: [String: LosslessJSONValue] = [ + "type": .string(sample.sampleType.identifier), + "start": .string(String(sample.startDate.timeIntervalSince1970)), + "end": .string(String(sample.endDate.timeIntervalSince1970)), + "metadata": .object(metadata.mapValues { .string(metadataText($0)) }) + ] + if let quantitySample = sample as? HKQuantitySample { + members["quantity"] = .string(quantityText(quantitySample.quantity, units: units)) + } + if let correlation = sample as? HKCorrelation { + let objects = correlation.objects.map { Self.sample($0, units: units) }.sorted { $0.canonicalText < $1.canonicalText } + members["objects"] = .array(objects) + } + return .object(members) + } + + /// A metadata value as text: a string as itself, a number as `NSNumber` prints it (a Boolean as 0 or 1). + private static func metadataText(_ value: Any) -> String { + switch value { + case let text as String: text + case let number as NSNumber: number.stringValue + default: String(describing: value) + } + } + + /// The HealthKit units of the quantities `observation` states, as the published unit bindings read them. + private static func statedUnits(of observation: Observation) -> [HKUnit] { + var quantities: [ModelsR4.Quantity] = [] + if case .quantity(let quantity)? = observation.value { + quantities.append(quantity) + } + for case .quantity(let quantity)? in (observation.component ?? []).map(\.value) { + quantities.append(quantity) + } + return quantities.compactMap { $0.code?.value?.string }.compactMap(HealthKitCatalog.unit(forUCUMCode:)) + } + + /// A quantity in the first stated unit that measures it: the unit the projection created it in. + private static func quantityText(_ quantity: HKQuantity, units: [HKUnit]) -> String { + guard let unit = units.first(where: quantity.is(compatibleWith:)) else { + return quantity.description + } + return "\(String(quantity.doubleValue(for: unit))) \(unit.unitString)" + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusRecorder.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusRecorder.swift index 5117275c1..2c6cc316b 100644 --- a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusRecorder.swift +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusRecorder.swift @@ -21,14 +21,17 @@ import ModelsR4 /// order; a refusal renders as its registry code, location and Swift error, and a policy omission as such. The rest /// of the envelope (Provenance, Devices) stays out: the goldens pin it. /// -/// Converted Observations are not projected back here: `Observation.healthKitSample()` builds the sample through -/// HealthKit's initializers, which raise an uncatchable exception for an instant HealthKit refuses (after 4000, or -/// shorter than a type's minimum duration). The `reverse/` vectors project curated Observations instead. +/// Port points for the cleanup step: every conversion and retraction here goes through the deprecated +/// `HealthKitConverter` facade (each call is marked `Port point`). When the facade is deleted they move to +/// `HealthKitFHIRExporter`, whose rendering of every convert vector `ContentCorpusExporterTests` already pins. enum ContentCorpusRecorder { /// What converting one source record produced. enum Outcome { + /// The record's graphs. case converted(HealthKitConversionSet) + /// A policy chose to emit nothing. case omitted + /// The record was refused. case refused(HealthKitConversionError) } @@ -50,7 +53,7 @@ enum ContentCorpusRecorder { /// Converts `source` through the entry point its record takes. static func outcome(of source: ContentCorpusSource) throws -> Outcome { let context = try context(for: source) - let converter = HealthKitConverter() + let converter = HealthKitConverter() // Port point: the deprecated facade. switch source.record { case .electrocardiogram(let reading): let record = try ContentCorpusSamples.electrocardiogram(source, reading: reading) @@ -58,28 +61,29 @@ enum ContentCorpusRecorder { try GoldenFixtures.context(sequence: sequence + 1 + UInt64(index)) } return capture { () throws(HealthKitConversionError) in - try converter.convert(record, context: context, symptomContexts: symptomContexts) + try converter.convert(record, context: context, symptomContexts: symptomContexts) // Port point. } case .heartbeatSeries(let beats): let record = try ContentCorpusSamples.heartbeatSeries(source, beats: beats) - return capture { () throws(HealthKitConversionError) in try converter.convert(record, context: context) } + return capture { () throws(HealthKitConversionError) in try converter.convert(record, context: context) } // Port point. case .workoutRoute(let locations, _): let record = try ContentCorpusSamples.workoutRoute(source, locations: locations) do { - return try converter.convert(record, context: context).map(Outcome.converted) ?? .omitted + return try converter.convert(record, context: context).map(Outcome.converted) ?? .omitted // Port point. } catch { return .refused(error) } default: let sample = try ContentCorpusSamples.sample(source) - return capture { () throws(HealthKitConversionError) in try converter.convert(sample, context: context) } + return capture { () throws(HealthKitConversionError) in try converter.convert(sample, context: context) } // Port point. } } + /// The tokens an outcome renders as. static func render(_ outcome: Outcome) throws -> LosslessJSONValue { switch outcome { case .converted(let set): - .object(["graphs": .array(try set.all.map(graph))]) + .object(["graphs": .array(try set.all.map { try graph($0.graph, warnings: GoldenOutput($0).renderedWarnings) })]) case .omitted: .object(["omitted": .boolean(true)]) case .refused(let error): @@ -87,8 +91,9 @@ enum ContentCorpusRecorder { } } - /// The suite's fixed context, under a gateway converter with one study when the vector asks for every link. - private static func context(for source: ContentCorpusSource) throws -> HealthKitConversionContext { + /// The suite's fixed context, under a gateway converter with one study when the vector asks for every link, + /// and with routes disclosed when its route is. + static func context(for source: ContentCorpusSource) throws -> HealthKitConversionContext { var inputs = GoldenFixtures.Inputs() if source.context == .linked { inputs.converterRole = .gateway @@ -100,15 +105,8 @@ enum ContentCorpusRecorder { return try GoldenFixtures.context(sequence: sequence, inputs) } - private static func capture(_ convert: () throws(HealthKitConversionError) -> HealthKitConversionSet) -> Outcome { - do { - return .converted(try convert()) - } catch { - return .refused(error) - } - } - - private static func refusal(_ error: HealthKitConversionError) -> LosslessJSONValue { + /// A refusal as its registry code, location and Swift error. + static func refusal(_ error: HealthKitConversionError) -> LosslessJSONValue { let refusal = LosslessJSONValue.object([ "code": .string(error.diagnostic.code), "location": .string(error.diagnostic.location), @@ -117,85 +115,28 @@ enum ContentCorpusRecorder { return .object(["refused": refusal]) } - /// One graph's output resources as its wire bytes state them, and its warnings. - private static func graph(_ conversion: HealthKitConversion) throws -> LosslessJSONValue { - let bundle = try LosslessJSONValue(parsing: conversion.graph.json) - let outputs = (bundle["entry"]?.elements ?? []).compactMap { $0["resource"] }.filter { resource in - outputResourceTypes.contains(resource["resourceType"]?.text ?? "") - } + /// One graph's output resources as its wire bytes state them, and its warnings as rendered. + static func graph(_ graph: ExchangeGraph, warnings: [String]) throws -> LosslessJSONValue { + let bundle = try LosslessJSONValue(parsing: graph.json) + let entries = bundle["entry"]?.elements ?? [] return .object([ - "outputs": .array(outputs), - "warnings": .array(GoldenOutput(conversion).renderedWarnings.map(LosslessJSONValue.string)) + "outputs": .array(entries.compactMap { $0["resource"] }.filter(isOutput)), + "warnings": .array(warnings.map(LosslessJSONValue.string)) ]) } - /// The deletion of a record of `type`: the targets it retracts, or why it retracts none. - private static func retraction(of type: String) throws -> LosslessJSONValue { - guard let sourceType = HealthKitSourceType(rawValue: type) else { - throw ContentCorpusSamples.RebuildError.unknownType(type) - } - let context = try GoldenFixtures.context(sequence: sequence) - let record = HealthKitSourceRecord(uuid: ContentCorpusSamples.uuid, type: sourceType) - do { - let targets = try HealthKitConverter().retractionTargets(for: record, context: context).map { target in - LosslessJSONValue.object([ - "identifier": .string(target.identifier.identifier.value), - "identifierRole": .string(target.identifier.role.rawValue), - "resourceType": .string(target.resourceType.rawValue), - "role": .string(target.role.rawValue) - ]) - } - return .object(["targets": .array(targets)]) - } catch { - return refusal(error) - } + /// Whether a resource is one the content layer produces. + private static func isOutput(_ resource: LosslessJSONValue) -> Bool { + outputResourceTypes.contains(resource["resourceType"]?.text ?? "") } - /// The sample `observation` projects back to, or why it does not. - static func reverse(_ observation: Observation) -> LosslessJSONValue { + /// The outcome of one conversion that either produces a set or refuses. + private static func capture(_ convert: () throws(HealthKitConversionError) -> HealthKitConversionSet) -> Outcome { do { - return sample(try observation.healthKitSample()) + return .converted(try convert()) } catch { - let refusal = LosslessJSONValue.object([ - "code": .string(error.diagnostic.code), - "error": .string(String(describing: error)) - ]) - return .object(["refused": refusal]) - } - } - - /// A projected sample's type, interval, metadata, value and members, every number as its shortest text. - private static func sample(_ sample: HKSample) -> LosslessJSONValue { - var members: [String: LosslessJSONValue] = [ - "type": .string(sample.sampleType.identifier), - "start": .string(String(sample.startDate.timeIntervalSince1970)), - "end": .string(String(sample.endDate.timeIntervalSince1970)), - "metadata": .object((sample.metadata ?? [:]).mapValues { .string(metadataText($0)) }) - ] - if let quantitySample = sample as? HKQuantitySample { - members["quantity"] = .string(quantityText(quantitySample.quantity)) - } - if let correlation = sample as? HKCorrelation { - let objects = correlation.objects.map(Self.sample).sorted { $0.canonicalText < $1.canonicalText } - members["objects"] = .array(objects) - } - return .object(members) - } - - private static func metadataText(_ value: Any) -> String { - switch value { - case let text as String: text - case let number as NSNumber: number.stringValue - default: String(describing: value) - } - } - - /// A quantity in the unit it was created with, which HealthKit keeps but does not publish. - private static func quantityText(_ quantity: HKQuantity) -> String { - guard let unit = quantity.value(forKey: "unit") as? HKUnit else { - return quantity.description + return .refused(error) } - return "\(String(quantity.doubleValue(for: unit))) \(unit.unitString)" } } diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusSamples+Recordings.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusSamples+Recordings.swift new file mode 100644 index 000000000..1c139d705 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusSamples+Recordings.swift @@ -0,0 +1,104 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import CoreLocation +import Foundation +@testable import GroveHealthKitFHIR +import HealthKit + + +/// The records that convert through their own entry points: an ECG with its voltages and symptoms, a heartbeat +/// series with its beats, and a workout route with its fixes. +extension ContentCorpusSamples { + /// The ECG record the record entry point takes; each symptom spans the ECG's interval in the default zone. + static func electrocardiogram(_ source: ContentCorpusSource, reading: ContentCorpusElectrocardiogram) throws -> HealthKitECGRecord { + let beatsPerMinute = HKUnit.count().unitDivided(by: .minute()) + let ecg = try StoredSampleFixtures.electrocardiogram( + facts: facts(source), + reading: StoredElectrocardiogram.Reading( + classification: try rawEnumeration(reading.classification, HKElectrocardiogram.Classification.init(rawValue:)), + symptomsStatus: try rawEnumeration(reading.symptomsStatus, HKElectrocardiogram.SymptomsStatus.init(rawValue:)), + numberOfVoltageMeasurements: reading.reportedCount, + averageHeartRate: reading.averageHeartRate.map { HKQuantity(unit: beatsPerMinute, doubleValue: $0) }, + samplingFrequency: reading.samplingFrequency.map { HKQuantity(unit: .hertz(), doubleValue: $0) } + ) + ) + var symptomSource = source + symptomSource.device = nil + symptomSource.writer = .unattributed + symptomSource.metadata = [HKMetadataKeyTimeZone: .string(GoldenFixtures.timeZone)] + return HealthKitECGRecord( + electrocardiogram: ecg, + voltageMeasurements: try reading.voltages.map { voltage in + try StoredSampleFixtures.voltageMeasurement(offset: voltage.offset, millivolts: voltage.millivolts) + }, + correlatedSymptoms: try reading.symptoms.map { symptom in + try StoredSampleFixtures.categorySample( + try categoryType(symptom.type), + value: symptom.value, + facts: facts(symptomSource, uuid: GoldenFixtures.uuid(symptom.ordinal)) + ) + } + ) + } + + /// The heartbeat series record the record entry point takes. + static func heartbeatSeries(_ source: ContentCorpusSource, beats: [ContentCorpusBeat]) throws -> HealthKitHeartbeatSeriesRecord { + HealthKitHeartbeatSeriesRecord( + series: try StoredSampleFixtures.seriesSample(HKHeartbeatSeriesSample.self, sampleType: HKSeriesType.heartbeat(), facts: facts(source)), + heartbeats: beats.map(\.heartbeat) + ) + } + + /// The workout route record the record entry point takes. + static func workoutRoute(_ source: ContentCorpusSource, locations: [ContentCorpusLocation]) throws -> HealthKitWorkoutRouteRecord { + let start = Date(timeIntervalSince1970: source.start) + return HealthKitWorkoutRouteRecord( + route: try StoredSampleFixtures.seriesSample(HKWorkoutRoute.self, sampleType: HKSeriesType.workoutRoute(), facts: facts(source)), + locations: locations.map { $0.location(after: start) } + ) + } + + /// An imported enumeration's case for any raw value, known to this SDK or not. + private static func rawEnumeration(_ raw: Int, _ make: (Int) -> Value?) throws -> Value { + guard let value = make(raw) else { + throw RebuildError.unstatable("raw value \(raw)") + } + return value + } +} + + +extension ContentCorpusBeat { + /// The beat as the converter's record states it. + var heartbeat: HealthKitHeartbeat { + HealthKitHeartbeat(timeSinceSeriesStart: offset, precededByGap: gap) + } +} + + +extension ContentCorpusLocation { + /// The fix as CoreLocation reports it, `offset` seconds after `start`. + func location(after start: Date) -> CLLocation { + CLLocation( + coordinate: CLLocationCoordinate2D(latitude: latitude, longitude: longitude), + altitude: altitude, + horizontalAccuracy: horizontalAccuracy, + verticalAccuracy: verticalAccuracy, + course: course, + courseAccuracy: courseAccuracy, + speed: speed, + speedAccuracy: speedAccuracy, + timestamp: start.addingTimeInterval(offset) + ) + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusSamples+Records.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusSamples+Records.swift deleted file mode 100644 index 66cf091a1..000000000 --- a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusSamples+Records.swift +++ /dev/null @@ -1,252 +0,0 @@ -// -// This source file is part of the Grove open-source project -// -// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) -// -// SPDX-License-Identifier: MIT -// - -#if canImport(HealthKit) - -import CoreLocation -import Foundation -@testable import GroveHealthKitFHIR -import HealthKit - - -/// The clinical samples, which watchOS does not have. -enum ContentCorpusClinicalSamples { - #if os(watchOS) - static func sample(_ record: ContentCorpusRecord, shape: StoredSampleFixtures.SeriesShape) throws -> HKSample { - throw ContentCorpusSamples.RebuildError.unknownClass("HKClinicalRecord") - } - #else - static func sample(_ record: ContentCorpusRecord, shape: StoredSampleFixtures.SeriesShape) throws -> HKSample { - switch record { - case let .cdaDocument(title, document): - return try cdaDocument(title: title, document: document, shape: shape) - case let .clinicalRecord(type, fhirVersion, resource): - return try clinicalRecord(type: type, fhirVersion: fhirVersion, resource: resource, shape: shape) - default: - throw ContentCorpusSamples.RebuildError.notASample - } - } - - /// A CDA sample as an `HKDocumentQuery` returns it, with its document data, or without when `document` is nil. - private static func cdaDocument(title: String, document: String?, shape: StoredSampleFixtures.SeriesShape) throws -> HKSample { - guard let documentType = HKObjectType.documentType(forIdentifier: .CDA) else { - throw ContentCorpusSamples.RebuildError.unknownType(HKDocumentTypeIdentifier.CDA.rawValue) - } - let sample = try StoredSampleFixtures.seriesSample(HKCDADocumentSample.self, sampleType: documentType, shape: shape) - guard let document else { - return sample - } - let content = try StoredSampleFixtures.allocate(HKCDADocument.self) - try StoredSampleFixtures.write(Data(document.utf8), to: "internalDocumentData", of: content) - try StoredSampleFixtures.write(title, to: "title", of: content) - try StoredSampleFixtures.write(content, to: "document", of: sample) - guard sample.document?.documentData == Data(document.utf8), sample.document?.title == title else { - throw ContentCorpusSamples.RebuildError.notHonored("CDA document") - } - return sample - } - - /// A clinical record carrying `resource` under `fhirVersion`, or no FHIR resource at all when it is nil. - private static func clinicalRecord( - type: String, - fhirVersion: String, - resource: String?, - shape: StoredSampleFixtures.SeriesShape - ) throws -> HKSample { - guard let clinicalType = HKObjectType.clinicalType(forIdentifier: HKClinicalTypeIdentifier(rawValue: type)) else { - throw ContentCorpusSamples.RebuildError.unknownType(type) - } - let record = try StoredSampleFixtures.seriesSample(HKClinicalRecord.self, sampleType: clinicalType, shape: shape) - guard let resource else { - return record - } - let content = try StoredSampleFixtures.allocate(HKFHIRResource.self) - try StoredSampleFixtures.write(Data(resource.utf8), to: "data", of: content) - try StoredSampleFixtures.write(try HKFHIRVersion(fromVersionString: fhirVersion), to: "FHIRVersion", of: content) - try StoredSampleFixtures.write(content, to: "FHIRResource", of: record) - guard record.fhirResource?.data == Data(resource.utf8) else { - throw ContentCorpusSamples.RebuildError.notHonored("FHIR resource") - } - return record - } - #endif -} - - -extension ContentCorpusSamples { - /// A workout, State of Mind or scored assessment stating exactly the vector's payload. - static func reflection(_ record: ContentCorpusRecord, shape: StoredSampleFixtures.SeriesShape) throws -> HKSample { - switch record { - case let .workout(activity, duration, statistics): - try workout(activity: activity, duration: duration, statistics: statistics, shape: shape) - case let .stateOfMind(kind, valence, labels, associations): - try stateOfMind(kind: kind, valence: valence, labels: labels, associations: associations, shape: shape) - case let .assessment(type, score): - try assessment(type: type, score: score, shape: shape) - default: - throw RebuildError.notASample - } - } - - /// The ECG record the record entry point takes; each symptom carries the ECG's interval and the default zone. - static func electrocardiogram(_ source: ContentCorpusSource, reading: ContentCorpusElectrocardiogram) throws -> HealthKitECGRecord { - let beatsPerMinute = HKUnit.count().unitDivided(by: .minute()) - let ecg = try StoredSampleFixtures.electrocardiogram( - shape: shape(source), - reading: StoredElectrocardiogram.Reading( - classification: try rawEnumeration(reading.classification, HKElectrocardiogram.Classification.init(rawValue:)), - symptomsStatus: try rawEnumeration(reading.symptomsStatus, HKElectrocardiogram.SymptomsStatus.init(rawValue:)), - numberOfVoltageMeasurements: reading.reportedCount, - averageHeartRate: reading.averageHeartRate.map { HKQuantity(unit: beatsPerMinute, doubleValue: $0) }, - samplingFrequency: reading.samplingFrequency.map { HKQuantity(unit: .hertz(), doubleValue: $0) } - ) - ) - var symptomSource = source - symptomSource.device = nil - symptomSource.writer = .unattributed - symptomSource.metadata = [HKMetadataKeyTimeZone: .string(GoldenFixtures.timeZone)] - return HealthKitECGRecord( - electrocardiogram: ecg, - voltageMeasurements: try reading.voltages.map { voltage in - try StoredSampleFixtures.voltageMeasurement(offset: voltage.offset, millivolts: voltage.millivolts) - }, - correlatedSymptoms: try reading.symptoms.map { symptom in - try category(type: symptom.type, value: symptom.value, shape: shape(symptomSource, uuid: GoldenFixtures.uuid(symptom.ordinal))) - } - ) - } - - static func heartbeatSeries(_ source: ContentCorpusSource, beats: [ContentCorpusBeat]) throws -> HealthKitHeartbeatSeriesRecord { - HealthKitHeartbeatSeriesRecord( - series: try StoredSampleFixtures.seriesSample(HKHeartbeatSeriesSample.self, sampleType: HKSeriesType.heartbeat(), shape: shape(source)), - heartbeats: beats.map { HealthKitHeartbeat(timeSinceSeriesStart: $0.offset, precededByGap: $0.gap) } - ) - } - - static func workoutRoute(_ source: ContentCorpusSource, locations: [ContentCorpusLocation]) throws -> HealthKitWorkoutRouteRecord { - let start = Date(timeIntervalSince1970: source.start) - return HealthKitWorkoutRouteRecord( - route: try StoredSampleFixtures.seriesSample(HKWorkoutRoute.self, sampleType: HKSeriesType.workoutRoute(), shape: shape(source)), - locations: locations.map { fix in - CLLocation( - coordinate: CLLocationCoordinate2D(latitude: fix.latitude, longitude: fix.longitude), - altitude: fix.altitude, - horizontalAccuracy: fix.horizontalAccuracy, - verticalAccuracy: fix.verticalAccuracy, - course: fix.course, - courseAccuracy: fix.courseAccuracy, - speed: fix.speed, - speedAccuracy: fix.speedAccuracy, - timestamp: start.addingTimeInterval(fix.offset) - ) - } - ) - } - - /// An imported enumeration's case for any raw value, known to this SDK or not. - private static func rawEnumeration(_ raw: Int, _ make: (Int) -> Value?) throws -> Value { - guard let value = make(raw) else { - throw RebuildError.notHonored("raw value \(raw)") - } - return value - } - - /// A workout of any activity raw value, duration and statistics; HealthKit computes statistics only while - /// recording one, so they are written into its primary activity. - private static func workout( - activity: UInt, - duration: Double, - statistics: [ContentCorpusStatistic], - shape: StoredSampleFixtures.SeriesShape - ) throws -> HKWorkout { - let workout = HKWorkout(activityType: .running, start: GoldenFixtures.sampleStart, end: GoldenFixtures.sampleStart.addingTimeInterval(60)) - try StoredSampleFixtures.write(NSNumber(value: activity), to: "workoutActivityType", of: workout) - try StoredSampleFixtures.write(NSNumber(value: duration), to: "duration", of: workout) - guard let primary = workout.value(forKey: "primaryActivity") as? NSObject, - let byType = primary.value(forKey: "statisticsPerType") as? NSMutableDictionary else { - throw RebuildError.notHonored("workout statistics") - } - for statistic in statistics { - let quantityType = try workoutStatisticType(statistic.type) - byType[quantityType] = try workoutStatistic(statistic, type: quantityType) - } - guard workout.workoutActivityType.rawValue == activity, workout.duration.bitPattern == duration.bitPattern, - workout.allStatistics.count == statistics.count else { - throw RebuildError.notHonored("workout activity, duration or statistics") - } - return try StoredSampleFixtures.restated(workout, shape: shape) - } - - private static func workoutStatisticType(_ type: String) throws -> HKQuantityType { - guard let quantityType = HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier(rawValue: type)) else { - throw RebuildError.unknownType(type) - } - return quantityType - } - - /// One statistics object with only the readings the vector states. - private static func workoutStatistic(_ statistic: ContentCorpusStatistic, type: HKQuantityType) throws -> NSObject { - let unit = HKUnit(from: statistic.unit) - guard type.is(compatibleWith: unit) else { - throw RebuildError.incompatibleUnit(type: statistic.type, unit: statistic.unit) - } - let object = try StoredSampleFixtures.allocate(HKStatistics.self) - try StoredSampleFixtures.write(type, to: "dataType", of: object) - let readings: [(key: String, value: Double?)] = [ - ("sumQuantity", statistic.sum), ("averageQuantity", statistic.average), - ("minimumQuantity", statistic.minimum), ("maximumQuantity", statistic.maximum) - ] - for reading in readings { - try StoredSampleFixtures.write(reading.value.map { HKQuantity(unit: unit, doubleValue: $0) }, to: reading.key, of: object) - } - return object - } - - /// A reflection of any kind and labels, which HealthKit refuses at creation unless it knows them. - private static func stateOfMind( - kind: Int, - valence: Double, - labels: [Int], - associations: [Int], - shape: StoredSampleFixtures.SeriesShape - ) throws -> HKStateOfMind { - // HealthKit classifies the valence when it is read and traps outside -1...1, so no vector states one. - guard (-1...1).contains(valence) else { - throw RebuildError.notHonored("valence \(valence)") - } - let reflection = HKStateOfMind(date: GoldenFixtures.sampleStart, kind: .momentaryEmotion, valence: 0, labels: [], associations: []) - try StoredSampleFixtures.write(NSNumber(value: kind), to: "kind", of: reflection) - try StoredSampleFixtures.write(NSNumber(value: valence), to: "valence", of: reflection) - try StoredSampleFixtures.write(labels.map { NSNumber(value: $0) }, to: "labels", of: reflection) - try StoredSampleFixtures.write(associations.map { NSNumber(value: $0) }, to: "associations", of: reflection) - guard reflection.kind.rawValue == kind, reflection.valence == valence, - reflection.labels.map(\.rawValue) == labels, reflection.associations.map(\.rawValue) == associations else { - throw RebuildError.notHonored("State of Mind") - } - return try StoredSampleFixtures.restated(reflection, shape: shape) - } - - /// A GAD-7 or PHQ-9 assessment stating any score. - private static func assessment(type: String, score: Int, shape: StoredSampleFixtures.SeriesShape) throws -> HKScoredAssessment { - let assessment: HKScoredAssessment = switch type { - case HKScoredAssessmentTypeIdentifier.GAD7.rawValue: - HKGAD7Assessment(date: GoldenFixtures.sampleStart, answers: Array(repeating: .notAtAll, count: 7)) - case HKScoredAssessmentTypeIdentifier.PHQ9.rawValue: - HKPHQ9Assessment(date: GoldenFixtures.sampleStart, answers: Array(repeating: .notAtAll, count: 9)) - default: - throw RebuildError.unknownType(type) - } - try StoredSampleFixtures.write(NSNumber(value: score), to: "score", of: assessment) - guard assessment.score == score else { - throw RebuildError.notHonored("assessment score") - } - return try StoredSampleFixtures.restated(assessment, shape: shape) - } -} - -#endif diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusSamples.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusSamples.swift index 568a7afb4..8cd169863 100644 --- a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusSamples.swift +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusSamples.swift @@ -8,31 +8,34 @@ #if canImport(HealthKit) -import CoreLocation import Foundation @testable import GroveHealthKitFHIR import HealthKit -/// Rebuilds a corpus vector's records the way HealthKit hands them back, through `StoredSampleFixtures`. -/// -/// Each sample starts from its class's public initializer with values HealthKit admits, or as a bare instance -/// where the class has none or would refuse the vector, and is then restated with the vector's exact facts. +/// Rebuilds a corpus vector's records the way HealthKit hands them back: it reads the vector's data into HealthKit +/// types and lets `StoredSampleFixtures`, the only code that touches HealthKit's private storage, build them. enum ContentCorpusSamples { + /// Why a vector's record cannot be rebuilt here. enum RebuildError: Error, CustomStringConvertible { + /// This HealthKit does not know the type identifier. case unknownType(String) + /// This HealthKit has no class of that name. case unknownClass(String) - case incompatibleUnit(type: String, unit: String) - case notHonored(String) + /// HealthKit would trap on the fact, so no sample can state it. + case unstatable(String) + /// The record converts through its own entry point, not as a plain sample. case notASample + /// This platform has no such record; the vector is verified on the others. + case unavailableHere(String) var description: String { switch self { case .unknownType(let type): "this HealthKit does not know \(type)" case .unknownClass(let name): "this HealthKit has no class \(name)" - case let .incompatibleUnit(type, unit): "\(unit) does not measure \(type)" - case .notHonored(let fact): "HealthKit no longer reads back the \(fact) the corpus writes" + case .unstatable(let fact): "HealthKit traps on \(fact), so no sample states it" case .notASample: "the record converts through its own entry point" + case .unavailableHere(let type): "this platform has no \(type)" } } } @@ -51,8 +54,8 @@ enum ContentCorpusSamples { ] /// Every fact of `source` except its payload, under `uuid`. - static func shape(_ source: ContentCorpusSource, uuid: UUID = uuid) -> StoredSampleFixtures.SeriesShape { - StoredSampleFixtures.SeriesShape( + static func facts(_ source: ContentCorpusSource, uuid: UUID = uuid) -> StoredSampleFixtures.SampleFacts { + StoredSampleFixtures.SampleFacts( uuid: uuid, start: Date(timeIntervalSince1970: source.start), end: Date(timeIntervalSince1970: source.end), @@ -64,123 +67,132 @@ enum ContentCorpusSamples { /// The sample a vector feeds the plain sample entry point. static func sample(_ source: ContentCorpusSource) throws -> HKSample { - let shape = shape(source) + let facts = facts(source) switch source.record { case let .quantity(type, value, unit): - return try quantity(type: type, value: value, unit: unit, shape: shape) + return try quantity(type: type, value: value, unit: unit, facts: facts) case let .category(type, value): - return try category(type: type, value: value, shape: shape) + return try StoredSampleFixtures.categorySample(try categoryType(type), value: value, facts: facts) case let .correlation(type, members): - return try correlation(type: type, members: members, shape: shape) - case let .bare(type, sampleClass): - return try bare(type: type, sampleClass: sampleClass, shape: shape) + return try correlation(type: type, members: members, facts: facts) case .workout, .stateOfMind, .assessment: - return try reflection(source.record, shape: shape) + return try initializedSample(source.record, facts: facts) + case let .bare(type, sampleClass): + return try bare(type: type, sampleClass: sampleClass, facts: facts) case .cdaDocument, .clinicalRecord: - return try ContentCorpusClinicalSamples.sample(source.record, shape: shape) + return try clinicalSample(source.record, facts: facts) case .electrocardiogram, .heartbeatSeries, .workoutRoute: throw RebuildError.notASample } } - /// A quantity sample of any value over any interval: HealthKit validates both per type at creation, so the - /// sample is a bare instance of the class its initializer would have chosen. - static func quantity(type: String, value: Double, unit: String, shape: StoredSampleFixtures.SeriesShape) throws -> HKQuantitySample { + /// A quantity sample stating `value` in `unit`. + static func quantity(type: String, value: Double, unit: String, facts: StoredSampleFixtures.SampleFacts) throws -> HKQuantitySample { + try StoredSampleFixtures.quantitySample(try quantityType(type), value: value, unit: HKUnit(from: unit), facts: facts) + } + + /// The quantity type an identifier names. + static func quantityType(_ type: String) throws -> HKQuantityType { guard let quantityType = HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier(rawValue: type)) else { throw RebuildError.unknownType(type) } - let healthKitUnit = HKUnit(from: unit) - guard quantityType.is(compatibleWith: healthKitUnit) else { - throw RebuildError.incompatibleUnit(type: type, unit: unit) - } - let sampleClass: HKQuantitySample.Type = quantityType.aggregationStyle == .cumulative - ? HKCumulativeQuantitySample.self - : HKDiscreteQuantitySample.self - let sample = try StoredSampleFixtures.seriesSample(sampleClass, sampleType: quantityType, shape: shape) - try StoredSampleFixtures.write(HKQuantity(unit: healthKitUnit, doubleValue: value), to: "quantity", of: sample) - try StoredSampleFixtures.write(NSNumber(value: 1), to: "count", of: sample) - let stated = sample.quantity.doubleValue(for: healthKitUnit) - guard stated == value || (stated.isNaN && value.isNaN) else { - throw RebuildError.notHonored("quantity") - } - return sample + return quantityType } - /// A category sample with any raw value: HealthKit refuses an unadmitted one at creation, so the sample is bare. - static func category(type: String, value: Int, shape: StoredSampleFixtures.SeriesShape) throws -> HKCategorySample { + /// The category type an identifier names. + static func categoryType(_ type: String) throws -> HKCategoryType { guard let categoryType = HKObjectType.categoryType(forIdentifier: HKCategoryTypeIdentifier(rawValue: type)) else { throw RebuildError.unknownType(type) } - let sample = try StoredSampleFixtures.seriesSample(HKCategorySample.self, sampleType: categoryType, shape: shape) - try StoredSampleFixtures.write(NSNumber(value: value), to: "value", of: sample) - guard sample.value == value else { - throw RebuildError.notHonored("category value") - } - return sample + return categoryType } - /// A correlation with exactly `members`, which HealthKit's initializer would refuse unless it is one valid pair. + /// A correlation of exactly `members`, each stating its own metadata, attributed to no writer and no device. private static func correlation( type: String, members: [ContentCorpusMember], - shape: StoredSampleFixtures.SeriesShape + facts: StoredSampleFixtures.SampleFacts ) throws -> HKCorrelation { - let identifier = HKCorrelationTypeIdentifier(rawValue: type) - guard let correlationType = HKObjectType.correlationType(forIdentifier: identifier) else { + guard let correlationType = HKObjectType.correlationType(forIdentifier: HKCorrelationTypeIdentifier(rawValue: type)) else { throw RebuildError.unknownType(type) } - let correlation = HKCorrelation( - type: correlationType, - start: GoldenFixtures.sampleStart, - end: GoldenFixtures.sampleStart, - objects: try placeholders(for: identifier) - ) - let objects = NSMutableDictionary() - for (index, member) in members.enumerated() { - var memberShape = shape - memberShape.uuid = GoldenFixtures.uuid(0xD0 + UInt8(index)) - memberShape.device = nil - memberShape.metadata = member.metadata.isEmpty ? nil : member.metadata.mapValues(\.value) - memberShape.writer = .unattributed - let sample = try quantity(type: member.type, value: member.value, unit: member.unit, shape: memberShape) - let group = objects[sample.sampleType] as? NSMutableSet ?? NSMutableSet() - group.add(sample) - objects[sample.sampleType] = group - } - try StoredSampleFixtures.write(objects, to: "objects", of: correlation) - guard correlation.objects.count == members.count else { - throw RebuildError.notHonored("correlation objects") + let objects = try members.enumerated().map { index, member in + var memberFacts = facts + memberFacts.uuid = GoldenFixtures.uuid(0xD0 + UInt8(index)) + memberFacts.device = nil + memberFacts.metadata = member.metadata.isEmpty ? nil : member.metadata.mapValues(\.value) + memberFacts.writer = .unattributed + return try quantity(type: member.type, value: member.value, unit: member.unit, facts: memberFacts) } - return try StoredSampleFixtures.restated(correlation, shape: shape) + return try StoredSampleFixtures.correlation(correlationType, objects: objects, facts: facts) } - /// Objects the correlation's initializer admits: a blood-pressure pair, or one food entry. They carry no writer, - /// the only attribution the initializer accepts for its objects, and are replaced by the vector's members. - private static func placeholders(for identifier: HKCorrelationTypeIdentifier) throws -> Set { - let pressure = HKUnit.millimeterOfMercury() - let objects: [(HKQuantityTypeIdentifier, HKQuantity)] = identifier == .bloodPressure - ? [(.bloodPressureSystolic, HKQuantity(unit: pressure, doubleValue: 120)), (.bloodPressureDiastolic, HKQuantity(unit: pressure, doubleValue: 80))] - : [(.dietaryEnergyConsumed, HKQuantity(unit: .kilocalorie(), doubleValue: 1))] - return Set(try objects.enumerated().map { index, object in - let sample = HKQuantitySample( - type: HKQuantityType(object.0), - quantity: object.1, - start: GoldenFixtures.sampleStart, - end: GoldenFixtures.sampleStart - ) - return try StoredSampleFixtures.stored(sample, uuid: GoldenFixtures.uuid(0xCE + UInt8(index))) - }) + /// A workout, State of Mind or scored assessment: built through its initializer, which validates the payload, + /// then restated with the vector's exact payload and facts. + private static func initializedSample(_ record: ContentCorpusRecord, facts: StoredSampleFixtures.SampleFacts) throws -> HKSample { + switch record { + case let .workout(activity, duration, statistics): + let statistics = try statistics.map { statistic in + StoredSampleFixtures.WorkoutStatistic( + type: try quantityType(statistic.type), + unit: HKUnit(from: statistic.unit), + sum: statistic.sum, + average: statistic.average, + minimum: statistic.minimum, + maximum: statistic.maximum + ) + } + return try StoredSampleFixtures.workout(activity: activity, duration: duration, statistics: statistics, facts: facts) + case let .stateOfMind(kind, valence, labels, associations): + // HealthKit classifies the valence when it is read and traps outside -1...1, so no vector states one. + guard (-1...1).contains(valence) else { + throw RebuildError.unstatable("valence \(valence)") + } + return try StoredSampleFixtures.stateOfMind(kind: kind, valence: valence, labels: labels, associations: associations, facts: facts) + case let .assessment(type, score): + let identifier = HKScoredAssessmentTypeIdentifier(rawValue: type) + guard let assessment = try StoredSampleFixtures.scoredAssessment(identifier, score: score, facts: facts) else { + throw RebuildError.unknownType(type) + } + return assessment + default: + throw RebuildError.notASample + } } /// A bare instance of a class the corpus feeds the plain entry point without a payload. - private static func bare(type: String, sampleClass: String, shape: StoredSampleFixtures.SeriesShape) throws -> HKSample { + private static func bare(type: String, sampleClass: String, facts: StoredSampleFixtures.SampleFacts) throws -> HKSample { guard let sampleType = bareSampleTypes[type] else { throw RebuildError.unknownType(type) } guard let healthKitClass = NSClassFromString(sampleClass) as? HKSample.Type else { throw RebuildError.unknownClass(sampleClass) } - return try StoredSampleFixtures.seriesSample(healthKitClass, sampleType: sampleType, shape: shape) + return try StoredSampleFixtures.seriesSample(healthKitClass, sampleType: sampleType, facts: facts) + } + + /// A CDA document or clinical record, which watchOS does not have. + private static func clinicalSample(_ record: ContentCorpusRecord, facts: StoredSampleFixtures.SampleFacts) throws -> HKSample { + #if os(watchOS) + throw RebuildError.unavailableHere(record.sourceTypeIdentifier) + #else + switch record { + case let .cdaDocument(title, document): + return try StoredSampleFixtures.cdaDocument(title: title, document: document.map { Data($0.utf8) }, facts: facts) + case let .clinicalRecord(type, fhirVersion, resource): + guard let clinicalType = HKObjectType.clinicalType(forIdentifier: HKClinicalTypeIdentifier(rawValue: type)) else { + throw RebuildError.unknownType(type) + } + return try StoredSampleFixtures.clinicalRecord( + clinicalType, + fhirVersion: try HKFHIRVersion(fromVersionString: fhirVersion), + resource: resource.map { Data($0.utf8) }, + facts: facts + ) + default: + throw RebuildError.notASample + } + #endif } } diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusStore.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusStore.swift index ca631cc12..2d584f5f3 100644 --- a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusStore.swift +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusStore.swift @@ -16,44 +16,61 @@ import Foundation /// /// The corpus is `Resources/ContentCorpus/content-corpus.jsonl`: one line per vector, an object with the vector's /// `id`, its `input` and its `output`, printed compactly with members sorted and output number lexemes kept. It is -/// regenerated exactly like the goldens, OUTSIDE the checkout: with `GROVE_GOLDEN_OUTPUT_DIR` set (under -/// `xcodebuild`, `TEST_RUNNER_GROVE_GOLDEN_OUTPUT_DIR`), the suite writes `content-corpus.jsonl` there, to be -/// copied in afterwards, and only in a commit whose diff is exactly the enumerated change of one fix. +/// regenerated OUTSIDE the checkout: +/// with `GROVE_CONTENT_CORPUS_OUTPUT_DIR` set (under `xcodebuild`, `TEST_RUNNER_GROVE_CONTENT_CORPUS_OUTPUT_DIR`), +/// the suite writes `content-corpus.jsonl` and `content-corpus.changes.txt` there, to be copied in (the corpus +/// only) afterwards, and only in a commit whose diff is exactly the enumerated change of one fix. enum ContentCorpusStore { - /// One checked-in line: its key, its input, and the output it pins. + /// One checked-in line: its key, its input, the output it pins, and its bytes as checked in. struct Line { + /// The vector's key. let id: String + /// The vector's input. let input: ContentCorpusInput + /// The output the line pins. let output: LosslessJSONValue + /// The line's bytes, without the newline. + let bytes: Data + + /// The vector the line states. + var vector: ContentCorpusVector { + ContentCorpusVector(id: id, input: input) + } } + /// A line that is not an object with an id, an input this schema reads, and an output. struct MalformedLine: Error, CustomStringConvertible { + /// The one-based line number. let number: Int + /// What could not be read. + let reason: String var description: String { - "content-corpus.jsonl line \(number) is not an object with an id, an input and an output" - } - } - - struct MissingCorpus: Error, CustomStringConvertible { - var description: String { - "No content-corpus.jsonl is checked in; regenerate with GROVE_GOLDEN_OUTPUT_DIR and copy it into Resources/ContentCorpus" + "content-corpus.jsonl line \(number) is not an object with an id, an input and an output: \(reason)" } } /// What a line states besides its output; read by Foundation, which keeps every string exactly. private struct Key: Decodable { + /// The line's key. let id: String + /// The line's input. let input: ContentCorpusInput } + /// The corpus's place in the bundle and its regeneration directory. + static let resources = CheckedInResources.contentCorpus + /// The corpus's file name. static let name = "content-corpus" + /// The corpus's file extension. static let fileExtension = "jsonl" + /// The change report a regeneration writes beside the corpus. + static let changesFile = "content-corpus.changes.txt" - static let outputDirectory: URL? = ProcessInfo.processInfo.environment["GROVE_GOLDEN_OUTPUT_DIR"] - .flatMap { $0.isEmpty ? nil : URL(fileURLWithPath: $0, isDirectory: true) } - - static var isGenerating: Bool { outputDirectory != nil } + /// Whether this run regenerates the corpus instead of verifying it. + static var isGenerating: Bool { + resources.isGenerating + } /// Sorted members, unescaped slashes, and non-finite inputs as strings, since JSON has no literal for them. private static var encoder: JSONEncoder { @@ -63,6 +80,7 @@ enum ContentCorpusStore { return encoder } + /// The decoder matching ``encoder``. private static var decoder: JSONDecoder { let decoder = JSONDecoder() decoder.nonConformingFloatDecodingStrategy = .convertFromString(positiveInfinity: "Infinity", negativeInfinity: "-Infinity", nan: "NaN") @@ -71,30 +89,28 @@ enum ContentCorpusStore { /// The checked-in corpus, whichever way the build system laid the resources out. static func checkedIn() throws -> Data { - guard let url = Bundle.module.url(forResource: name, withExtension: fileExtension, subdirectory: "ContentCorpus") - ?? Bundle.module.url(forResource: name, withExtension: fileExtension) else { - throw MissingCorpus() - } - return try Data(contentsOf: url) + try resources.data(named: name, withExtension: fileExtension) + } + + /// The lines of `data` with their one-based numbers, without the newlines. + static func rawLines(_ data: Data) -> [(number: Int, bytes: Data)] { + data.split(separator: UInt8(ascii: "\n"), omittingEmptySubsequences: true).enumerated().map { ($0 + 1, Data($1)) } } /// Reads the lines of `data` whose zero-based number leaves `shard.index` modulo `shard.count`, one at a time, /// so the corpus is never held as parsed tokens all at once. static func forEachLine(in data: Data, shard: (index: Int, count: Int) = (0, 1), _ body: (Line) throws -> Void) throws { - for (number, slice) in data.split(separator: UInt8(ascii: "\n"), omittingEmptySubsequences: true).enumerated() - where number % shard.count == shard.index { + for (number, bytes) in rawLines(data) where (number - 1) % shard.count == shard.index { try autoreleasepool { - try body(try line(Data(slice), number: number + 1)) + try body(try line(bytes, number: number)) } } } /// Every line's id and input, in order, leaving the outputs unread. static func vectors(in data: Data) throws -> [ContentCorpusVector] { - try data.split(separator: UInt8(ascii: "\n"), omittingEmptySubsequences: true).enumerated().map { number, slice in - guard let key = try? decoder.decode(Key.self, from: Data(slice)) else { - throw MalformedLine(number: number + 1) - } + try rawLines(data).map { number, bytes in + let key = try key(bytes, number: number) return ContentCorpusVector(id: key.id, input: key.input) } } @@ -106,83 +122,38 @@ enum ContentCorpusStore { /// The line a vector and its output print as. static func line(_ vector: ContentCorpusVector, output: LosslessJSONValue) throws -> String { - let id = String(decoding: try encoder.encode(vector.id), as: UTF8.self) - let input = try inputText(vector.input) - return #"{"id":\#(id),"input":\#(input),"output":\#(output.canonicalText)}"# + let id = LosslessJSONValue.string(vector.id).canonicalText + return #"{"id":\#(id),"input":\#(try inputText(vector.input)),"output":\#(output.canonicalText)}"# } - /// Writes the regenerated corpus into the output directory. - static func write(_ lines: [String]) throws { - guard let directory = outputDirectory else { - return - } - try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true) - let text = lines.map { $0 + "\n" }.joined() - try Data(text.utf8).write(to: directory.appendingPathComponent("\(name).\(fileExtension)")) + /// Writes the regenerated corpus and its change report into the regeneration directory. + static func write(_ lines: [String], changes: ContentCorpusChanges) throws { + try resources.write(Data(lines.map { $0 + "\n" }.joined().utf8), toFile: "\(name).\(fileExtension)") + try resources.write(Data(changes.report.utf8), toFile: changesFile) } - private static func line(_ data: Data, number: Int) throws -> Line { - guard let key = try? decoder.decode(Key.self, from: data), - let output = (try? LosslessJSONValue(parsing: data))?["output"] else { - throw MalformedLine(number: number) + /// The id and input of line `number`. + private static func key(_ bytes: Data, number: Int) throws -> Key { + do { + return try decoder.decode(Key.self, from: bytes) + } catch { + throw MalformedLine(number: number, reason: String(describing: error)) } - return Line(id: key.id, input: key.input, output: output) - } -} - - -extension LosslessJSONValue { - /// Compact JSON with members sorted by key and every number lexeme kept as read: two values print alike exactly - /// when their tokens are equal, so a corpus line diffs by content. - var canonicalText: String { - var text = "" - append(to: &text) - return text } - private static func append(_ string: String, to text: inout String) { - text.append("\"") - for scalar in string.unicodeScalars { - switch scalar { - case "\"": text.append("\\\"") - case "\\": text.append("\\\\") - case "\n": text.append("\\n") - case "\r": text.append("\\r") - case "\t": text.append("\\t") - case _ where scalar.value < 0x20: text.append(String(format: "\\u%04x", scalar.value)) - default: text.unicodeScalars.append(scalar) - } + /// Line `number` read whole. + private static func line(_ bytes: Data, number: Int) throws -> Line { + let key = try key(bytes, number: number) + let tokens: LosslessJSONValue + do { + tokens = try LosslessJSONValue(parsing: bytes) + } catch { + throw MalformedLine(number: number, reason: String(describing: error)) } - text.append("\"") - } - - private func append(to text: inout String) { - switch self { - case .object(let members): - text.append("{") - for (index, key) in members.keys.sorted().enumerated() { - text.append(index == 0 ? "" : ",") - Self.append(key, to: &text) - text.append(":") - members[key]?.append(to: &text) - } - text.append("}") - case .array(let elements): - text.append("[") - for (index, element) in elements.enumerated() { - text.append(index == 0 ? "" : ",") - element.append(to: &text) - } - text.append("]") - case .string(let string): - Self.append(string, to: &text) - case .number(let lexeme): - text.append(lexeme) - case .boolean(let flag): - text.append(flag ? "true" : "false") - case .null: - text.append("null") + guard let output = tokens["output"] else { + throw MalformedLine(number: number, reason: "no output") } + return Line(id: key.id, input: key.input, output: output, bytes: bytes) } } diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusTests.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusTests.swift index d95266eeb..8c82e7c35 100644 --- a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusTests.swift +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusTests.swift @@ -16,46 +16,50 @@ import Testing /// The content corpus, oracle O2 of the HealthKit content rewrite: every checked-in vector converts to exactly the -/// tokens its line pins, the grid that generates the corpus still states exactly the checked-in inputs, and every -/// output a conversion emits is one the catalog names for its source type. +/// tokens and bytes its line pins, the grid that generates the corpus still states exactly the checked-in inputs, +/// and every output a conversion emits is one the catalog names for its source type. /// /// The corpus was recorded from the content builders the rewrite replaces, so any change in content output fails /// here with the vector and the first differing path. A deliberate change regenerates the corpus (see -/// `ContentCorpusStore`) in the one commit whose enumerated diff it is. +/// `ContentCorpusStore`) in the one commit whose enumerated diff it is; `content-corpus.changes.txt` lists that +/// diff. Regenerating the goldens leaves the corpus verified: each family has its own environment variable. @Suite struct ContentCorpusTests { /// The corpus splits into this many shards, which run in parallel. static let shards = 8 - /// Whether this platform can rebuild a vector: watchOS has no clinical records or CDA documents. - static func isAvailableHere(_ id: String) -> Bool { - #if os(watchOS) - !id.hasPrefix("cda/") && !id.hasPrefix("clinical/") - #else - true - #endif + /// The tokens a checked-in line's vector converts to now, checking that every emitted output is cataloged, or + /// nil when this platform cannot rebuild the vector's record. + private static func reproduction(of line: ContentCorpusStore.Line, uncataloged: inout [String]) throws -> LosslessJSONValue? { + do { + guard case .convert(let source) = line.input else { + return try ContentCorpusRecorder.output(for: line.input) + } + let outcome = try ContentCorpusRecorder.outcome(of: source) + uncataloged += try ContentCorpusInvariants.uncatalogedOutputs(of: outcome, source: source).map { "\(line.id): \($0)" } + return try ContentCorpusRecorder.render(outcome) + } catch ContentCorpusSamples.RebuildError.unavailableHere { + return nil + } } + /// Reproduces one shard. A vector whose record this platform does not have (watchOS has no clinical records or + /// CDA documents) is skipped; every other vector must rebuild, convert to the pinned tokens, and print as the + /// pinned bytes, which also catches what token equality cannot see (canonically equivalent strings). @Test(.enabled(if: !ContentCorpusStore.isGenerating), arguments: 0.. 0, "shard \(shard) of the corpus is empty") @@ -63,26 +67,36 @@ struct ContentCorpusTests { #expect(uncataloged.isEmpty, "\(uncataloged.count) emitted outputs the catalog does not name: \(uncataloged.prefix(25))") } - /// The generator and the file agree line for line, and ids are unique. + /// The generator and the file agree line for line, and ids are unique; a failure names the first difference. @Test(.enabled(if: !ContentCorpusStore.isGenerating)) func gridIsTheCheckedInCorpus() throws { - let grid = ContentCorpusGrid.vectors.filter { Self.isAvailableHere($0.id) } - let checkedIn = try ContentCorpusStore.vectors(in: ContentCorpusStore.checkedIn()).filter { Self.isAvailableHere($0.id) } + let grid = ContentCorpusGrid.vectors + let checkedIn = try ContentCorpusStore.vectors(in: ContentCorpusStore.checkedIn()) let ids = grid.map(\.id) - let stray = Set(checkedIn.map(\.id)).subtracting(ids).sorted().prefix(10) - let missing = Set(ids).subtracting(checkedIn.map(\.id)).sorted().prefix(10) - #expect(Set(ids).count == ids.count, "the grid names a vector twice") - #expect(checkedIn.map(\.id) == ids, "lines without a vector: \(stray); vectors without a line: \(missing)") - let changed = try zip(grid, checkedIn).compactMap { vector, line in + let duplicates = Dictionary(grouping: ids, by: \.self).filter { $0.value.count > 1 }.keys.sorted() + #expect(duplicates.isEmpty, "the grid names vectors twice: \(duplicates.prefix(10))") + let stray = Set(checkedIn.map(\.id)).subtracting(ids).sorted() + let missing = Set(ids).subtracting(checkedIn.map(\.id)).sorted() + #expect(stray.isEmpty, "\(stray.count) lines without a vector: \(stray.prefix(10))") + #expect(missing.isEmpty, "\(missing.count) vectors without a line: \(missing.prefix(10))") + if let index = zip(ids, checkedIn.map(\.id)).enumerated().first(where: { $1.0 != $1.1 })?.offset { + Issue.record("the grid orders vectors differently from line \(index + 1): \(ids[index]) where the corpus has \(checkedIn[index].id)") + } + let restated = try zip(grid, checkedIn).compactMap { vector, line in try ContentCorpusStore.inputText(vector.input) == ContentCorpusStore.inputText(line.input) ? nil : vector.id } - #expect(changed.isEmpty, "the grid states other inputs than the corpus: \(changed.prefix(10))") + #expect(restated.isEmpty, "\(restated.count) vectors state other inputs than the corpus: \(restated.prefix(10))") } - /// With `GROVE_GOLDEN_OUTPUT_DIR` set, records every vector twice, requires identical tokens, and writes the - /// corpus there. Regenerate on macOS (the gate's platform), never on watchOS, whose grid has no clinical documents. + /// With `GROVE_CONTENT_CORPUS_OUTPUT_DIR` set, records every vector twice, requires identical tokens, compares + /// the result with the checked-in corpus, and writes the corpus and `content-corpus.changes.txt` there. It + /// writes nothing when a vector converts nondeterministically, or when the regeneration drops or duplicates an + /// id or restates an input `GROVE_CONTENT_CORPUS_ALLOW_RESTATED_INPUTS` does not admit. Regenerate on macOS. @Test(.enabled(if: ContentCorpusStore.isGenerating)) func corpusRegenerates() throws { + #if os(watchOS) + Issue.record("regenerate the corpus on macOS: watchOS has no clinical records to rebuild") + #else var lines: [String] = [] var nondeterministic: [String] = [] for vector in ContentCorpusGrid.vectors { @@ -94,8 +108,14 @@ struct ContentCorpusTests { lines.append(try ContentCorpusStore.line(vector, output: output)) } } - #expect(nondeterministic.isEmpty, "vectors that do not convert deterministically: \(nondeterministic)") - try ContentCorpusStore.write(lines) + try #require(nondeterministic.isEmpty, "vectors that do not convert deterministically: \(nondeterministic)") + let changes = try ContentCorpusChanges(checkedIn: ContentCorpusStore.checkedIn(), regenerated: lines) + try #require(changes.removed.isEmpty, "the regeneration drops ids: \(changes.removed.prefix(25))") + try #require(changes.duplicated.isEmpty, "the regeneration names ids twice: \(changes.duplicated.prefix(25))") + let unallowed = changes.unallowedRestatements + try #require(unallowed.isEmpty, "the regeneration restates the inputs of \(unallowed.count) ids (\(unallowed.prefix(10))); see ContentCorpusChanges") + try ContentCorpusStore.write(lines, changes: changes) + #endif } } diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentInvariantTests.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentInvariantTests.swift index e7aece41b..8c0fa4415 100644 --- a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentInvariantTests.swift +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentInvariantTests.swift @@ -17,16 +17,17 @@ import Testing /// Invariant checks over one conversion, shared by the corpus pass so no vector converts twice. enum ContentCorpusInvariants { - /// Every output a conversion emitted that its source type's catalog outputs do not name, and a primary output - /// that is not the catalog's first: identity enters only through the catalog's (role, discriminator) pairs. - static func uncatalogedOutputs(of outcome: ContentCorpusRecorder.Outcome) throws -> [String] { + /// Every output a conversion of `source` emitted that its source type's catalog outputs do not name, and a + /// primary output that is not the catalog's first: identity enters only through the catalog's (role, + /// discriminator) pairs, minted under the context the vector converted under. + static func uncatalogedOutputs(of outcome: ContentCorpusRecorder.Outcome, source: ContentCorpusSource) throws -> [String] { guard case .converted(let set) = outcome else { return [] } - let context = try GoldenFixtures.context(sequence: ContentCorpusRecorder.sequence) + let context = try ContentCorpusRecorder.context(for: source) return try set.all.flatMap { conversion -> [String] in let record = try context.identityScope.sourceRecord( - adapterID: "healthkit", + adapterID: HealthKitConverter.adapterID, sourceType: conversion.source.type.rawValue, repositoryScope: context.event.repositoryScope, nativeRecordID: conversion.source.uuid.uuidString.lowercased() @@ -67,13 +68,19 @@ struct ContentInvariantTests { private static let notSampleTypes: Set = Set(ContentCorpusGrid.rows(prefix: "HKCharacteristicTypeIdentifier").map(\.sourceTypeIdentifier)) .union(["HKDataTypeUserAnnotatedMedicationConcept"]) + /// Every generated measurement contract by id, the first catalog winning; unlike the corpus grid's, it follows + /// the catalogs wherever they go. + private static let contracts: [String: MeasurementContract] = Dictionary( + (MeasurementCatalog.all + HealthKitMeasurementCatalog.all).map { ($0.id, $0) } + ) { first, _ in first } + /// Quantity rows that convert in a published unit binding: each one's unit measures its type. private static var boundQuantityRows: [(row: HealthKitContractRow, unit: HKUnit)] { ContentCorpusGrid.rows(prefix: "HKQuantityTypeIdentifier").compactMap { row in guard row.implementationStatus == .supported, let type = HealthKitSourceType(rawValue: row.sourceTypeIdentifier), !HealthKitCatalog.outputs(for: type).isEmpty, - let code = ContentCorpusGrid.contract(row)?.quantity?.code, + let code = row.measurementIDs.first.flatMap({ contracts[$0] })?.quantity?.code, let unit = HealthKitCatalog.unit(forUCUMCode: code) else { return nil } @@ -111,7 +118,8 @@ struct ContentInvariantTests { let type = try #require(HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier(rawValue: row.sourceTypeIdentifier))) #expect(type.is(compatibleWith: unit), "\(row.sourceTypeIdentifier) cannot be read in \(unit.unitString)") } - // The 108 unit-read quantity rows, less body-mass index, whose contract no generated catalog carries yet. + // The 108 unit-read quantity rows, less body-mass index, whose contract no generated catalog carries yet. M1 + // (generator G3) generates it; should it join a catalog's `all`, this count becomes 108 (see ContentCorpusGrid). #expect(bound.count == 107, "\(bound.count) quantity rows convert through a unit binding") for binding in HealthKitCatalog.unitBindings { let byCode = try #require(HealthKitCatalog.unit(forUCUMCode: binding.ucumCode)) @@ -150,12 +158,7 @@ struct ContentInvariantTests { } return source.record.sourceTypeIdentifier }) - let rows = Set(HealthKitContract.rows.map(\.sourceTypeIdentifier)).subtracting(Self.notSampleTypes) - #if os(watchOS) - let missing = rows.subtracting(converted).filter { !$0.hasPrefix("HKClinicalTypeIdentifier") && $0 != "HKDocumentTypeIdentifierCDA" } - #else - let missing = rows.subtracting(converted) - #endif + let missing = Set(HealthKitContract.rows.map(\.sourceTypeIdentifier)).subtracting(Self.notSampleTypes).subtracting(converted) #expect(missing.isEmpty, "rows without a conversion vector: \(missing.sorted())") } } diff --git a/Tests/GroveHealthKitFHIRTests/ExchangeEnvelopeFixTests.swift b/Tests/GroveHealthKitFHIRTests/ExchangeEnvelopeFixTests.swift index 551a88257..e87780440 100644 --- a/Tests/GroveHealthKitFHIRTests/ExchangeEnvelopeFixTests.swift +++ b/Tests/GroveHealthKitFHIRTests/ExchangeEnvelopeFixTests.swift @@ -55,7 +55,7 @@ struct ExchangeEnvelopeFixTests { let series = try StoredSampleFixtures.seriesSample( HKHeartbeatSeriesSample.self, sampleType: HKSeriesType.heartbeat(), - shape: GoldenCase.seriesShape(uuid: ordinal, duration: 2) + facts: GoldenCase.seriesFacts(uuid: ordinal, duration: 2) ) return HealthKitHeartbeatSeriesRecord(series: series, heartbeats: [ HealthKitHeartbeat(timeSinceSeriesStart: 0, precededByGap: false), @@ -110,9 +110,9 @@ struct ExchangeEnvelopeFixTests { [HKMetadataKeyTimeZone: GoldenFixtures.timeZone, HKMetadataKeySyncIdentifier: "series-1", HKMetadataKeySyncVersion: 1.5] ] for metadata in malformed { - var shape = GoldenCase.seriesShape(uuid: 89, duration: 2) - shape.metadata = metadata - let series = try StoredSampleFixtures.seriesSample(HKHeartbeatSeriesSample.self, sampleType: HKSeriesType.heartbeat(), shape: shape) + var facts = GoldenCase.seriesFacts(uuid: 89, duration: 2) + facts.metadata = metadata + let series = try StoredSampleFixtures.seriesSample(HKHeartbeatSeriesSample.self, sampleType: HKSeriesType.heartbeat(), facts: facts) let record = HealthKitHeartbeatSeriesRecord(series: series, heartbeats: [HealthKitHeartbeat(timeSinceSeriesStart: 0, precededByGap: false)]) #expect(throws: HealthKitConversionError.invalidValue(.heartbeatSeries, .invalidMetadataValue(.syncVersion))) { try HealthKitConverter().convert(record, context: HealthKitConversionContext()) diff --git a/Tests/GroveHealthKitFHIRTests/ExporterCompanionFingerprintTests.swift b/Tests/GroveHealthKitFHIRTests/ExporterCompanionFingerprintTests.swift index 82e8c1c9f..1aa826e6e 100644 --- a/Tests/GroveHealthKitFHIRTests/ExporterCompanionFingerprintTests.swift +++ b/Tests/GroveHealthKitFHIRTests/ExporterCompanionFingerprintTests.swift @@ -90,7 +90,7 @@ struct ExporterCompanionFingerprintTests { let series = try StoredSampleFixtures.seriesSample( HKHeartbeatSeriesSample.self, sampleType: HKSeriesType.heartbeat(), - shape: GoldenCase.seriesShape(uuid: 0xF0, duration: 2) + facts: GoldenCase.seriesFacts(uuid: 0xF0, duration: 2) ) var changedBeats = Self.beats changedBeats[1] = HealthKitHeartbeat(timeSinceSeriesStart: 0.85, precededByGap: false) @@ -106,7 +106,7 @@ struct ExporterCompanionFingerprintTests { let route = try StoredSampleFixtures.seriesSample( HKWorkoutRoute.self, sampleType: HKSeriesType.workoutRoute(), - shape: GoldenCase.seriesShape(uuid: 0xF1, duration: 1) + facts: GoldenCase.seriesFacts(uuid: 0xF1, duration: 1) ) var changedLocations = GoldenCase.routeLocations let moved = changedLocations[1] diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift index 77b73ca73..0798a8411 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Documents.swift @@ -8,7 +8,6 @@ #if canImport(HealthKit) -import CoreLocation import Foundation import GroveFHIRContract @testable import GroveHealthKitFHIR @@ -27,9 +26,12 @@ enum GoldenCaseError: Error { extension GoldenCase { /// Sequences 60-79: graphs whose source has no public initializer, built on stored-sample fixtures. /// - /// The ECG goes through `HealthKitAssembly.convertECG(_:evidence:symptoms:request:symptomRequests:)`, the - /// internal seam below the public entry point, because the evidence an `HKElectrocardiogram` reports lives in - /// private storage the fixtures do not write; the envelope sample is a real `HKElectrocardiogram` nonetheless. + /// The ECG goes through `HealthKitConverter.convertECG(_:evidence:symptoms:context:symptomContexts:)`, the + /// internal seam that takes the ECG's evidence as given; the envelope sample is a real `HKElectrocardiogram` + /// nonetheless. These goldens predate `StoredSampleFixtures.electrocardiogram(facts:reading:)`, which states a + /// whole reading, so the content corpus converts its ECGs through the public record entry point instead. Both + /// state the same reading (`ContentCorpusGrid.electrocardiogramReading`), as the series and route state the + /// corpus's beats and fixes. static let documents: [GoldenCase] = [ GoldenCase("electrocardiogram", sequence: 60) { sequence in try GoldenOutput(primaryOf: electrocardiogram(uuid: 60, sequence: sequence, symptom: nil)) @@ -48,20 +50,16 @@ extension GoldenCase { let series = try StoredSampleFixtures.seriesSample( HKHeartbeatSeriesSample.self, sampleType: HKSeriesType.heartbeat(), - shape: seriesShape(uuid: 62, duration: 2) + facts: seriesFacts(uuid: 62, duration: 2) ) - let record = HealthKitHeartbeatSeriesRecord(series: series, heartbeats: [ - HealthKitHeartbeat(timeSinceSeriesStart: 0, precededByGap: false), - HealthKitHeartbeat(timeSinceSeriesStart: 0.84, precededByGap: false), - HealthKitHeartbeat(timeSinceSeriesStart: 1.71, precededByGap: true) - ]) + let record = HealthKitHeartbeatSeriesRecord(series: series, heartbeats: ContentCorpusGrid.heartbeats.map(\.heartbeat)) return try GoldenOutput(primaryOf: HealthKitConverter().convert(record, context: GoldenFixtures.context(sequence: sequence))) }, GoldenCase("workout-route", sequence: 63) { sequence in let route = try StoredSampleFixtures.seriesSample( HKWorkoutRoute.self, sampleType: HKSeriesType.workoutRoute(), - shape: seriesShape(uuid: 63, duration: 1) + facts: seriesFacts(uuid: 63, duration: 1) ) var inputs = GoldenFixtures.Inputs() inputs.options.routeDisclosure = .authorized @@ -131,31 +129,8 @@ extension GoldenCase { ] #endif - /// Two fixes one second apart; the second one reports no vertical accuracy, course or speed. - static let routeLocations = [ - CLLocation( - coordinate: CLLocationCoordinate2D(latitude: 37.4275, longitude: -122.1697), - altitude: 30.5, - horizontalAccuracy: 5, - verticalAccuracy: 3, - course: 91.5, - courseAccuracy: 10, - speed: 2.25, - speedAccuracy: 0.5, - timestamp: GoldenFixtures.sampleStart - ), - CLLocation( - coordinate: CLLocationCoordinate2D(latitude: 37.4276, longitude: -122.1698), - altitude: 0, - horizontalAccuracy: 65, - verticalAccuracy: -1, - course: -1, - courseAccuracy: -1, - speed: -1, - speedAccuracy: -1, - timestamp: GoldenFixtures.sampleStart.addingTimeInterval(1) - ) - ] + /// The corpus's two fixes one second apart; the second one reports no vertical accuracy, course or speed. + static let routeLocations = ContentCorpusGrid.routeLocations.map { $0.location(after: GoldenFixtures.sampleStart) } static let clinicalDocumentXML = """ @@ -205,12 +180,13 @@ extension GoldenCase { static func electrocardiogramEvidence( uuid ordinal: UInt8, symptomsPresent: Bool, - averageHeartRate: Double? = 72, + averageHeartRate: Double? = ContentCorpusGrid.electrocardiogramReading.averageHeartRate, timeZoned: Bool = true ) throws -> (sample: HKElectrocardiogram, evidence: HealthKitECGEvidence) { - var shape = seriesShape(uuid: ordinal, duration: 30) - shape.metadata = timeZoned ? shape.metadata : [:] - let ecg = try StoredSampleFixtures.seriesSample(HKElectrocardiogram.self, sampleType: HKObjectType.electrocardiogramType(), shape: shape) + var facts = seriesFacts(uuid: ordinal, duration: 30) + facts.metadata = timeZoned ? facts.metadata : [:] + let ecg = try StoredSampleFixtures.seriesSample(HKElectrocardiogram.self, sampleType: HKObjectType.electrocardiogramType(), facts: facts) + let reading = ContentCorpusGrid.electrocardiogramReading let source = HealthKitECGSourceEvidence( sourceTypeIdentifier: HealthKitContract.electrocardiogramSourceTypeIdentifier, startDate: GoldenFixtures.sampleStart, @@ -218,20 +194,15 @@ extension GoldenCase { timeZone: try HealthKitConverter.healthKitTimeZone(for: ecg), classification: .sinusRhythm, symptomsStatus: symptomsPresent ? .present : .none, - numberOfVoltageMeasurements: 4, + numberOfVoltageMeasurements: reading.reportedCount, averageHeartRate: averageHeartRate, - samplingFrequency: 500, + samplingFrequency: reading.samplingFrequency, algorithmVersion: HKAppleECGAlgorithmVersion.version2.rawValue ) let waveform = try HealthKitECGEvidenceValidator.validateWaveform( reportedCount: source.numberOfVoltageMeasurements, samplingFrequencyHertz: source.samplingFrequency, - points: [ - HealthKitECGVoltagePoint(timeSinceSampleStart: 0.250, millivolts: 0.125), - HealthKitECGVoltagePoint(timeSinceSampleStart: 0.252, millivolts: 0.250), - HealthKitECGVoltagePoint(timeSinceSampleStart: 0.254, millivolts: -0.125), - HealthKitECGVoltagePoint(timeSinceSampleStart: 0.256, millivolts: 0) - ] + points: reading.voltages.map { HealthKitECGVoltagePoint(timeSinceSampleStart: $0.offset, millivolts: $0.millivolts ?? .nan) } ) return (ecg, HealthKitECGEvidence(source: source, waveform: waveform)) } @@ -254,8 +225,8 @@ extension GoldenCase { } /// A series recorded by the watch, written by the foreign application. - static func seriesShape(uuid ordinal: UInt8, duration: TimeInterval) -> StoredSampleFixtures.SeriesShape { - StoredSampleFixtures.SeriesShape( + static func seriesFacts(uuid ordinal: UInt8, duration: TimeInterval) -> StoredSampleFixtures.SampleFacts { + StoredSampleFixtures.SampleFacts( uuid: GoldenFixtures.uuid(ordinal), start: GoldenFixtures.sampleStart, end: GoldenFixtures.sampleStart.addingTimeInterval(duration), diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Exporter.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Exporter.swift index 9520730ef..921d859f6 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Exporter.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphCases+Exporter.swift @@ -102,10 +102,10 @@ enum ExporterGolden { /// A lab result the provider issued in `version`, carried byte for byte. static func clinicalRecord(uuid ordinal: UInt8, version: HKFHIRVersion, payload: String) throws -> HKClinicalRecord { try StoredSampleFixtures.clinicalRecord( - .labResultRecord, - shape: GoldenCase.seriesShape(uuid: ordinal, duration: 0), - displayName: "Hemoglobin A1c", - resource: StoredSampleFixtures.ClinicalResource(version: version, type: .observation, identifier: "a1c", data: Data(payload.utf8)) + HKClinicalType(.labResultRecord), + fhirVersion: version, + resource: Data(payload.utf8), + facts: GoldenCase.seriesFacts(uuid: ordinal, duration: 0) ) } #endif diff --git a/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift index d2f2433e2..4694788f5 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenGraphTests.swift @@ -20,25 +20,14 @@ import Testing /// /// Goldens are regenerated OUTSIDE the checkout: `GROVE_GOLDEN_OUTPUT_DIR` (under `xcodebuild`, pass it as /// `TEST_RUNNER_GROVE_GOLDEN_OUTPUT_DIR`) names a directory the suite writes every case into, and the files are -/// copied into `Resources/Goldens/` afterwards. Writing into the checkout while Xcode runs the tests makes it -/// re-resolve the package graph mid-run. A regeneration run compares nothing, so it fails on purpose: it can -/// never be mistaken for a green golden run. +/// copied into `Resources/Goldens/` afterwards (see ``CheckedInResources``). The content corpus has its own +/// variable, so regenerating the goldens leaves it verified. A regeneration run compares nothing, so it fails on +/// purpose: it can never be mistaken for a green golden run. enum GoldenStore { - struct MissingGolden: Error, CustomStringConvertible { - let name: String - - var description: String { - "No golden '\(name).json' is checked in; regenerate with GROVE_GOLDEN_OUTPUT_DIR and copy it into Resources/Goldens" - } - } - - static let subdirectory = "Goldens" + /// The file pinning every case's outline. static let outlinesName = "outlines" - - static let outputDirectory: URL? = ProcessInfo.processInfo.environment["GROVE_GOLDEN_OUTPUT_DIR"] - .flatMap { $0.isEmpty ? nil : URL(fileURLWithPath: $0, isDirectory: true) } - - static var isGenerating: Bool { outputDirectory != nil } + /// The goldens' place in the bundle and their regeneration directory. + static let resources = CheckedInResources.goldens /// Sorted members and no escaped slashes, so a regenerated golden diffs by content; the comparison reads tokens, not text. static var encoder: JSONEncoder { @@ -47,23 +36,12 @@ enum GoldenStore { return encoder } - /// Every checked-in golden's name, whichever way the build system laid the resources out: `.process` flattens the - /// subdirectory, and a lookup under a subdirectory that is not there answers an empty array, not nil. - static var checkedInNames: Set { - let urls = [subdirectory, nil] - .compactMap { Bundle.module.urls(forResourcesWithExtension: "json", subdirectory: $0) } - .first { !$0.isEmpty } ?? [] - return Set(urls.map { $0.deletingPathExtension().lastPathComponent }) - } - + /// One checked-in golden's bytes. static func data(named name: String) throws -> Data { - guard let url = Bundle.module.url(forResource: name, withExtension: "json", subdirectory: subdirectory) - ?? Bundle.module.url(forResource: name, withExtension: "json") else { - throw MissingGolden(name: name) - } - return try Data(contentsOf: url) + try resources.data(named: name, withExtension: "json") } + /// Every case's pinned outline, by case name. static func outlines() throws -> [String: GoldenOutline] { try JSONDecoder().decode([String: GoldenOutline].self, from: data(named: outlinesName)) } @@ -105,50 +83,6 @@ struct GoldenOutline: Codable, Equatable { } -/// Names the first path where two token trees differ. -enum TokenDiff { - /// The first path where two token trees differ, or nil when they are equal. - static func firstDifference(expected: LosslessJSONValue, actual: LosslessJSONValue, at path: String = "$") -> String? { - switch (expected, actual) { - case let (.object(lhs), .object(rhs)): - for key in Set(lhs.keys).union(rhs.keys).sorted() { - guard let left = lhs[key] else { - return "\(path).\(key): golden has no such member, actual is \(rhs[key].map(describe) ?? "")" - } - guard let right = rhs[key] else { - return "\(path).\(key): missing, golden has \(describe(left))" - } - if let difference = firstDifference(expected: left, actual: right, at: "\(path).\(key)") { - return difference - } - } - // Every value matched under a dictionary lookup, which finds canonically equivalent names alike. - return expected == actual ? nil : "\(path): a member name differs in its Unicode scalars" - case let (.array(lhs), .array(rhs)): - for (index, pair) in zip(lhs, rhs).enumerated() { - if let difference = firstDifference(expected: pair.0, actual: pair.1, at: "\(path)[\(index)]") { - return difference - } - } - return lhs.count == rhs.count ? nil : "\(path): golden has \(lhs.count) elements, actual has \(rhs.count)" - default: - return expected == actual ? nil : "\(path): golden \(describe(expected)), actual \(describe(actual))" - } - } - - private static func describe(_ value: LosslessJSONValue) -> String { - switch value { - case .object(let members): "object(\(members.count) members)" - case .array(let elements): "array(\(elements.count))" - case .string(let text): "\"" + text.unicodeScalars.map { $0.isASCII ? String($0) : "\\u{\(String($0.value, radix: 16))}" }.joined() + "\"" - case .number(let lexeme): lexeme - case .boolean(let flag): "\(flag)" - case .null: "null" - } - } -} - - /// Pins the converter's current wire output, token for token, so the refactor can be proven identical. /// /// Each case converts fixed inputs through the OLD API and compares the graph's stored JSON (`ExchangeGraph.json`, @@ -156,7 +90,7 @@ enum TokenDiff { /// and decimal lexemes are not. A failure names the first differing path. @Suite struct GoldenGraphTests { - @Test(.enabled(if: !GoldenStore.isGenerating), arguments: GoldenCase.all) + @Test(.enabled(if: !GoldenStore.resources.isGenerating), arguments: GoldenCase.all) func matchesCheckedInGolden(_ goldenCase: GoldenCase) throws { let output = try goldenCase.output() let actual = try LosslessJSONValue(parsing: output.graph.json) @@ -184,7 +118,7 @@ struct GoldenGraphTests { @Test func everyCheckedInGoldenBelongsToACase() throws { let cases = Set(GoldenCase.all.map(\.name)) - let checkedIn = GoldenStore.checkedInNames + let checkedIn = GoldenStore.resources.names(withExtension: "json") #expect(checkedIn.isSuperset(of: cases), "cases without a golden: \(cases.subtracting(checkedIn).sorted())") let strays = checkedIn.subtracting(cases).subtracting([GoldenStore.outlinesName]).subtracting(GoldenCase.unavailableHere) #expect(strays.isEmpty, "goldens without a case: \(strays.sorted())") @@ -215,13 +149,10 @@ struct GoldenGraphTests { let event = graph.eventIdentifier.identifier.value #expect(events.updateValue(goldenCase.name, forKey: event) == nil, "\(goldenCase.name) shares its event with \(events[event] ?? "")") - if let directory = GoldenStore.outputDirectory { - try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true) - try sorted.write(to: directory.appendingPathComponent("\(goldenCase.name).json")) - } + try GoldenStore.resources.write(sorted, toFile: "\(goldenCase.name).json") } - if let directory = GoldenStore.outputDirectory { - try GoldenStore.encoder.encode(outlines).write(to: directory.appendingPathComponent("\(GoldenStore.outlinesName).json")) + try GoldenStore.resources.write(GoldenStore.encoder.encode(outlines), toFile: "\(GoldenStore.outlinesName).json") + if let directory = GoldenStore.resources.outputDirectory { Issue.record("Regenerated \(outlines.count) goldens into \(directory.path) and compared none: copy them into Resources/Goldens and rerun") } } @@ -310,7 +241,11 @@ struct GoldenGraphTests { let renamed = try tokens(#"{"entry":[{"fullUrl":"a","resource":{"valueX":72}}],"timestamp":"t"}"#) #expect(TokenDiff.firstDifference(expected: golden, actual: reordered) == nil) #expect(TokenDiff.firstDifference(expected: golden, actual: lexeme) == "$.entry[0].resource.value: golden 72, actual 72.0") - #expect(TokenDiff.firstDifference(expected: golden, actual: longer) == "$.entry: golden has 1 elements, actual has 2") + #expect(TokenDiff.firstDifference(expected: golden, actual: longer) == "$.entry[1]: golden has no such member, actual is object(1 members)") + #expect(TokenDiff.differences(expected: golden, actual: renamed).map(\.change) == [ + "$.entry[0].resource.value: 72 -> (absent)", + "$.entry[0].resource.valueX: (absent) -> 72" + ]) #expect(TokenDiff.firstDifference(expected: golden, actual: renamed) == "$.entry[0].resource.value: missing, golden has 72") #expect(GoldenOutline(golden, warnings: []) == GoldenOutline(reordered, warnings: [])) #expect(GoldenOutline(golden, warnings: []) != GoldenOutline(longer, warnings: [])) @@ -341,30 +276,6 @@ struct GoldenGraphTests { } -extension LosslessJSONValue { - var elements: [LosslessJSONValue]? { // swiftlint:disable:this discouraged_optional_collection - guard case .array(let elements) = self else { - return nil - } - return elements - } - - var text: String? { - guard case .string(let text) = self else { - return nil - } - return text - } - - subscript(member: String) -> LosslessJSONValue? { - guard case .object(let members) = self else { - return nil - } - return members[member] - } -} - - extension GoldenCase { /// Goldens generated on macOS for cases this platform cannot build. static var unavailableHere: Set { diff --git a/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift b/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift index ff8507db4..9d677fbc8 100644 --- a/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift +++ b/Tests/GroveHealthKitFHIRTests/GoldenOutputRevisionTests.swift @@ -106,7 +106,7 @@ struct GoldenOutputRevisionTests { func everyGoldenHasARow() { let rows = Set(Self.table.map(\.name)) #expect(rows.count == Self.table.count, "a golden is named twice") - let checkedIn = GoldenStore.checkedInNames + let checkedIn = GoldenStore.resources.names(withExtension: "json") #expect(checkedIn.subtracting(rows).isEmpty, "goldens without a revision row: \(checkedIn.subtracting(rows).sorted())") let stale = rows.subtracting(checkedIn).subtracting(GoldenCase.unavailableHere) #expect(stale.isEmpty, "rows without a golden: \(stale.sorted())") diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitECGEvidenceValidatorTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitECGEvidenceValidatorTests.swift index 2541f0cee..c38e3f4ca 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitECGEvidenceValidatorTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitECGEvidenceValidatorTests.swift @@ -119,7 +119,7 @@ struct HealthKitECGEvidenceValidatorTests { @Test("An ECG's source evidence states the sample's own classification, symptoms, rate, algorithm and zone") func sourceEvidenceReadsTheSample() throws { let start = GoldenFixtures.sampleStart - let shape = StoredSampleFixtures.SeriesShape( + let facts = StoredSampleFixtures.SampleFacts( uuid: GoldenFixtures.uuid(0xC0), start: start, end: start.addingTimeInterval(30), @@ -127,12 +127,13 @@ struct HealthKitECGEvidenceValidatorTests { metadata: [HKMetadataKeyTimeZone: GoldenFixtures.timeZone, HKMetadataKeyAppleECGAlgorithmVersion: HKAppleECGAlgorithmVersion.version2.rawValue], writer: GoldenFixtures.foreignWriter ) - let ecg = try StoredSampleFixtures.electrocardiogram( - shape: shape, - reading: (privateClassification: 4, classification: .atrialFibrillation), + let ecg = try StoredSampleFixtures.electrocardiogram(facts: facts, reading: StoredElectrocardiogram.Reading( + classification: .atrialFibrillation, symptomsStatus: .present, - averageHeartRate: HKQuantity(unit: GoldenFixtures.beatsPerMinute, doubleValue: 112) - ) + numberOfVoltageMeasurements: 0, + averageHeartRate: HKQuantity(unit: GoldenFixtures.beatsPerMinute, doubleValue: 112), + samplingFrequency: nil + )) let evidence = try HealthKitConverter.ecgSourceEvidence(ecg) #expect(evidence.sourceTypeIdentifier == HealthKitContract.electrocardiogramSourceTypeIdentifier) #expect(evidence.startDate == start) @@ -142,7 +143,7 @@ struct HealthKitECGEvidenceValidatorTests { #expect(evidence.symptomsStatus == .present) #expect(evidence.averageHeartRate == 112) #expect(evidence.algorithmVersion == HKAppleECGAlgorithmVersion.version2.rawValue) - // Unset voltages report no measurements and no sampling frequency. + // A reading without voltages reports no measurements and no sampling frequency. #expect(evidence.numberOfVoltageMeasurements == 0) #expect(evidence.samplingFrequency == nil) } @@ -188,7 +189,7 @@ struct HealthKitECGEvidenceValidatorTests { let ecg = try StoredSampleFixtures.seriesSample( HKElectrocardiogram.self, sampleType: HKObjectType.electrocardiogramType(), - shape: StoredSampleFixtures.SeriesShape( + facts: StoredSampleFixtures.SampleFacts( uuid: GoldenFixtures.uuid(0xC2), start: start, end: start.addingTimeInterval(30), diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterRecordTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterRecordTests.swift index ba30a9104..b78bd769e 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterRecordTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterRecordTests.swift @@ -87,7 +87,7 @@ struct HealthKitFHIRExporterRecordTests { let series = try StoredSampleFixtures.seriesSample( HKHeartbeatSeriesSample.self, sampleType: HKSeriesType.heartbeat(), - shape: GoldenCase.seriesShape(uuid: 0xE2, duration: 2) + facts: GoldenCase.seriesFacts(uuid: 0xE2, duration: 2) ) let (exports, _) = try Self.exports([.heartbeatSeries(series, beats: Self.beats)], exporter) try #require(exports.count == 1) @@ -106,7 +106,7 @@ struct HealthKitFHIRExporterRecordTests { let route = try StoredSampleFixtures.seriesSample( HKWorkoutRoute.self, sampleType: HKSeriesType.workoutRoute(), - shape: GoldenCase.seriesShape(uuid: 0xE3, duration: 1) + facts: GoldenCase.seriesFacts(uuid: 0xE3, duration: 1) ) let (exports, _) = try Self.exports([.workoutRoute(route, locations: GoldenCase.routeLocations)], exporter) try #require(exports.count == 1) @@ -125,7 +125,7 @@ struct HealthKitFHIRExporterRecordTests { let route = try StoredSampleFixtures.seriesSample( HKWorkoutRoute.self, sampleType: HKSeriesType.workoutRoute(), - shape: GoldenCase.seriesShape(uuid: 0xE4, duration: 1) + facts: GoldenCase.seriesFacts(uuid: 0xE4, duration: 1) ) let heartRate = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(0xE5)) let (exports, receipt) = try Self.exports([.workoutRoute(route, locations: GoldenCase.routeLocations), .sample(heartRate)], exporter) diff --git a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift index 0c9e1d900..f0ef285db 100644 --- a/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift +++ b/Tests/GroveHealthKitFHIRTests/HealthKitFHIRExporterTests.swift @@ -120,7 +120,7 @@ struct HealthKitFHIRExporterTests { let ecg = try StoredSampleFixtures.seriesSample( HKElectrocardiogram.self, sampleType: HKObjectType.electrocardiogramType(), - shape: GoldenCase.seriesShape(uuid: 4, duration: 30) + facts: GoldenCase.seriesFacts(uuid: 4, duration: 30) ) let heartRate = try GoldenFixtures.heartRate(uuid: GoldenFixtures.uuid(5)) let (exports, receipt) = try Self.collect(exporter, [ecg, heartRate]) diff --git a/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures+Corpus.swift b/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures+Corpus.swift new file mode 100644 index 000000000..faa330b0f --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures+Corpus.swift @@ -0,0 +1,272 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +import HealthKit +import ObjectiveC + + +/// TEST-ONLY. An `HKElectrocardiogram` that states its whole reading itself. +/// +/// HealthKit keeps an ECG's voltage count and sampling frequency in a C++ reading key-value coding cannot reach, +/// and derives its classification from a private enumeration, so a stored ECG answers those five properties +/// from the reading `StoredSampleFixtures.electrocardiogram(facts:reading:)` attaches. Every other fact lives +/// where HealthKit keeps it. +final class StoredElectrocardiogram: HKElectrocardiogram, @unchecked Sendable { + /// What an ECG reports about its recording. + struct Reading: Sendable { + /// The rhythm the recording was classified as, any raw value. + var classification: HKElectrocardiogram.Classification + /// Whether the user reported symptoms, any raw value. + var symptomsStatus: HKElectrocardiogram.SymptomsStatus + /// How many voltages HealthKit reports the recording to have. + var numberOfVoltageMeasurements: Int + /// The average heart rate over the recording. + var averageHeartRate: HKQuantity? + /// How often the lead was sampled. + var samplingFrequency: HKQuantity? + } + + /// The association key; only its address matters. + nonisolated(unsafe) private static var readingKey: UInt8 = 0 + + override var classification: Classification { reading.classification } + override var symptomsStatus: SymptomsStatus { reading.symptomsStatus } + override var numberOfVoltageMeasurements: Int { reading.numberOfVoltageMeasurements } + override var averageHeartRate: HKQuantity? { reading.averageHeartRate } + override var samplingFrequency: HKQuantity? { reading.samplingFrequency } + + /// The reading attached when the ECG was built. + private var reading: Reading { + guard let reading = objc_getAssociatedObject(self, &Self.readingKey) as? Reading else { + preconditionFailure("A stored ECG states its reading when it is built") + } + return reading + } + + /// Attaches the reading every overridden property answers from. + fileprivate func state(_ reading: Reading) { + objc_setAssociatedObject(self, &Self.readingKey, reading, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } +} + + +/// The per-class builders of the content corpus: each states one payload HealthKit would refuse at creation, +/// or keeps where only its own recording code writes it, then the sample's facts. +extension StoredSampleFixtures { + /// One statistic of a workout: its quantity type and the readings HealthKit reported, each in `unit`; an absent + /// reading is one HealthKit did not report. + struct WorkoutStatistic { + /// The statistic's quantity type. + let type: HKQuantityType + /// The unit every reading is stated in. + let unit: HKUnit + /// The cumulative reading. + let sum: Double? + /// The average reading. + let average: Double? + /// The smallest reading. + let minimum: Double? + /// The largest reading. + let maximum: Double? + } + + /// A quantity sample of any value over any interval: HealthKit validates both per type when it creates one, + /// so this is a bare instance of the class its initializer would have chosen. + static func quantitySample(_ type: HKQuantityType, value: Double, unit: HKUnit, facts: SampleFacts) throws -> HKQuantitySample { + guard type.is(compatibleWith: unit) else { + throw FixtureError.incompatibleUnit(unit: unit.unitString, type: type.identifier) + } + let sampleClass: HKQuantitySample.Type = type.aggregationStyle == .cumulative + ? HKCumulativeQuantitySample.self + : HKDiscreteQuantitySample.self + let sample = try seriesSample(sampleClass, sampleType: type, facts: facts) + try restate(sample, with: ["quantity": HKQuantity(unit: unit, doubleValue: value), "count": NSNumber(value: 1)]) + let stated = sample.quantity.doubleValue(for: unit) + guard stated == value || (stated.isNaN && value.isNaN) else { + throw FixtureError.keyNotHonored(key: "quantity", class: String(describing: sampleClass)) + } + return sample + } + + /// A category sample of any raw value; HealthKit refuses an unadmitted one at creation, so this is bare. + static func categorySample(_ type: HKCategoryType, value: Int, facts: SampleFacts) throws -> HKCategorySample { + let sample = try seriesSample(HKCategorySample.self, sampleType: type, facts: facts) + try restate(sample, with: ["value": NSNumber(value: value)]) + guard sample.value == value else { + throw FixtureError.keyNotHonored(key: "value", class: "HKCategorySample") + } + return sample + } + + /// A correlation of exactly `objects`, which HealthKit's initializer refuses unless they are one valid set. + /// + /// The correlation is built around placeholder objects it admits (a blood-pressure pair, or one food entry, + /// attributed to no writer as the initializer requires) and then states `objects` and `facts`. + static func correlation(_ type: HKCorrelationType, objects: [HKSample], facts: SampleFacts) throws -> HKCorrelation { + let correlation = HKCorrelation( + type: type, + start: GoldenFixtures.sampleStart, + end: GoldenFixtures.sampleStart, + objects: try correlationPlaceholders(for: type) + ) + let byType = NSMutableDictionary() + for object in objects { + let group = byType[object.sampleType] as? NSMutableSet ?? NSMutableSet() + group.add(object) + byType[object.sampleType] = group + } + try restate(correlation, with: ["objects": byType]) + guard correlation.objects.count == objects.count else { + throw FixtureError.keyNotHonored(key: "objects", class: "HKCorrelation") + } + return try restated(correlation, facts: facts) + } + + /// A workout of any activity raw value, duration and statistics; HealthKit computes statistics only while it + /// records a workout, so they are stated in the workout's primary activity. + static func workout(activity: UInt, duration: TimeInterval, statistics: [WorkoutStatistic], facts: SampleFacts) throws -> HKWorkout { + let workout = HKWorkout(activityType: .running, start: GoldenFixtures.sampleStart, end: GoldenFixtures.sampleStart.addingTimeInterval(60)) + try restate(workout, with: ["workoutActivityType": NSNumber(value: activity), "duration": NSNumber(value: duration)]) + guard let primary = try read("primaryActivity", of: workout) as? NSObject, + let byType = try read("statisticsPerType", of: primary) as? NSMutableDictionary else { + throw FixtureError.keyNotHonored(key: "primaryActivity/statisticsPerType", class: "HKWorkout") + } + for statistic in statistics { + guard statistic.type.is(compatibleWith: statistic.unit) else { + throw FixtureError.incompatibleUnit(unit: statistic.unit.unitString, type: statistic.type.identifier) + } + let quantity = { (reading: Double?) in reading.map { HKQuantity(unit: statistic.unit, doubleValue: $0) } } + byType[statistic.type] = try instance(of: HKStatistics.self, stating: [ + "dataType": statistic.type, "sumQuantity": quantity(statistic.sum), "averageQuantity": quantity(statistic.average), + "minimumQuantity": quantity(statistic.minimum), "maximumQuantity": quantity(statistic.maximum) + ]) + } + guard workout.workoutActivityType.rawValue == activity, workout.duration.bitPattern == duration.bitPattern, + workout.allStatistics.count == statistics.count else { + throw FixtureError.keyNotHonored(key: "workoutActivityType/duration/statisticsPerType", class: "HKWorkout") + } + return try restated(workout, facts: facts) + } + + /// A reflection of any kind, valence, labels and associations; HealthKit refuses kinds and labels it does not + /// know at creation. + static func stateOfMind(kind: Int, valence: Double, labels: [Int], associations: [Int], facts: SampleFacts) throws -> HKStateOfMind { + let reflection = HKStateOfMind(date: GoldenFixtures.sampleStart, kind: .momentaryEmotion, valence: 0, labels: [], associations: []) + try restate(reflection, with: [ + "kind": NSNumber(value: kind), "valence": NSNumber(value: valence), + "labels": labels.map { NSNumber(value: $0) }, "associations": associations.map { NSNumber(value: $0) } + ]) + guard reflection.kind.rawValue == kind, reflection.valence == valence, + reflection.labels.map(\.rawValue) == labels, reflection.associations.map(\.rawValue) == associations else { + throw FixtureError.keyNotHonored(key: "kind/valence/labels/associations", class: "HKStateOfMind") + } + return try restated(reflection, facts: facts) + } + + /// A GAD-7 or PHQ-9 assessment stating any score; nil for another assessment type. + static func scoredAssessment(_ type: HKScoredAssessmentTypeIdentifier, score: Int, facts: SampleFacts) throws -> HKScoredAssessment? { + let assessment: HKScoredAssessment + switch type { + case .GAD7: + assessment = HKGAD7Assessment(date: GoldenFixtures.sampleStart, answers: Array(repeating: .notAtAll, count: 7)) + case .PHQ9: + assessment = HKPHQ9Assessment(date: GoldenFixtures.sampleStart, answers: Array(repeating: .notAtAll, count: 9)) + default: + return nil + } + try restate(assessment, with: ["score": NSNumber(value: score)]) + guard assessment.score == score else { + throw FixtureError.keyNotHonored(key: "score", class: String(describing: Swift.type(of: assessment))) + } + return try restated(assessment, facts: facts) + } + + /// An ECG carrying exactly `facts` and stating `reading` as HealthKit would report it. + static func electrocardiogram(facts: SampleFacts, reading: StoredElectrocardiogram.Reading) throws -> HKElectrocardiogram { + let ecg = try seriesSample(StoredElectrocardiogram.self, sampleType: HKObjectType.electrocardiogramType(), facts: facts) + ecg.state(reading) + return ecg + } + + /// One voltage of an ECG's lead, or a measurement that states no lead voltage at all. + static func voltageMeasurement(offset: TimeInterval, millivolts: Double?) throws -> HKElectrocardiogram.VoltageMeasurement { + let measurement = try instance(of: HKElectrocardiogram.VoltageMeasurement.self, stating: [ + "timeSinceSampleStart": NSNumber(value: offset), + "leadIVoltage": millivolts.map { HKQuantity(unit: .voltUnit(with: .milli), doubleValue: $0) } + ]) + guard measurement.timeSinceSampleStart.bitPattern == offset.bitPattern, + (measurement.quantity(for: .appleWatchSimilarToLeadI) == nil) == (millivolts == nil) else { + throw FixtureError.keyNotHonored(key: "timeSinceSampleStart/leadIVoltage", class: "HKElectrocardiogram.VoltageMeasurement") + } + return measurement + } + + /// Objects the correlation's initializer admits: a blood-pressure pair, or one food entry. + private static func correlationPlaceholders(for type: HKCorrelationType) throws -> Set { + let pressure = HKUnit.millimeterOfMercury() + let objects: [(HKQuantityTypeIdentifier, HKQuantity)] = if type.identifier == HKCorrelationTypeIdentifier.bloodPressure.rawValue { + [ + (.bloodPressureSystolic, HKQuantity(unit: pressure, doubleValue: 120)), + (.bloodPressureDiastolic, HKQuantity(unit: pressure, doubleValue: 80)) + ] + } else { + [(.dietaryEnergyConsumed, HKQuantity(unit: .kilocalorie(), doubleValue: 1))] + } + return Set(try objects.enumerated().map { index, object in + let sample = HKQuantitySample( + type: HKQuantityType(object.0), + quantity: object.1, + start: GoldenFixtures.sampleStart, + end: GoldenFixtures.sampleStart + ) + return try stored(sample, uuid: GoldenFixtures.uuid(0xCE + UInt8(index))) + }) + } +} + + +#if !os(watchOS) +/// The clinical builders, which watchOS does not have. +extension StoredSampleFixtures { + /// A CDA sample as an `HKDocumentQuery` returns it: with its document data, or without when `document` is nil. + static func cdaDocument(title: String, document: Data?, facts: SampleFacts) throws -> HKCDADocumentSample { + guard let documentType = HKObjectType.documentType(forIdentifier: .CDA) else { + throw FixtureError.classNotConstructible("HKCDADocumentSample") + } + let sample = try seriesSample(HKCDADocumentSample.self, sampleType: documentType, facts: facts) + guard let document else { + return sample + } + let content = try instance(of: HKCDADocument.self, stating: ["internalDocumentData": document, "title": title]) + try restate(sample, with: ["document": content]) + guard sample.document?.documentData == document, sample.document?.title == title else { + throw FixtureError.keyNotHonored(key: "document", class: "HKCDADocumentSample") + } + return sample + } + + /// A clinical record carrying `resource` under `fhirVersion`, or no FHIR resource at all when it is nil. + static func clinicalRecord(_ type: HKClinicalType, fhirVersion: HKFHIRVersion, resource: Data?, facts: SampleFacts) throws -> HKClinicalRecord { + let record = try seriesSample(HKClinicalRecord.self, sampleType: type, facts: facts) + guard let resource else { + return record + } + let content = try instance(of: HKFHIRResource.self, stating: ["data": resource, "FHIRVersion": fhirVersion]) + try restate(record, with: ["FHIRResource": content]) + guard record.fhirResource?.data == resource else { + throw FixtureError.keyNotHonored(key: "FHIRResource", class: "HKClinicalRecord") + } + return record + } +} +#endif + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift b/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift index eeebcb0ba..864d95b20 100644 --- a/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift +++ b/Tests/GroveHealthKitFHIRTests/StoredSampleFixtures.swift @@ -13,66 +13,21 @@ import HealthKit import ObjectiveC -/// TEST-ONLY. An `HKElectrocardiogram` that states its whole reading itself. -/// -/// HealthKit keeps an ECG's voltage count and sampling frequency in a C++ reading key-value coding cannot reach, -/// and derives its classification from a private enumeration, so a stored ECG answers those five properties -/// from the reading `StoredSampleFixtures.electrocardiogram(shape:reading:)` attaches. Every other fact lives -/// where HealthKit keeps it. -final class StoredElectrocardiogram: HKElectrocardiogram, @unchecked Sendable { - /// What an ECG reports about its recording. - struct Reading: Sendable { - var classification: HKElectrocardiogram.Classification - var symptomsStatus: HKElectrocardiogram.SymptomsStatus - var numberOfVoltageMeasurements: Int - var averageHeartRate: HKQuantity? - var samplingFrequency: HKQuantity? - } - - /// The reading, as an object the runtime can associate with the instance. - private final class Statement: NSObject { - let reading: Reading - - init(_ reading: Reading) { - self.reading = reading - } - } - - /// The association key; only its address matters. - nonisolated(unsafe) private static var readingKey: UInt8 = 0 - - override var classification: Classification { reading.classification } - override var symptomsStatus: SymptomsStatus { reading.symptomsStatus } - override var numberOfVoltageMeasurements: Int { reading.numberOfVoltageMeasurements } - override var averageHeartRate: HKQuantity? { reading.averageHeartRate } - override var samplingFrequency: HKQuantity? { reading.samplingFrequency } - - private var reading: Reading { - guard let statement = objc_getAssociatedObject(self, &Self.readingKey) as? Statement else { - preconditionFailure("A stored ECG states its reading when it is built") - } - return statement.reading - } - - /// Attaches the reading every overridden property answers from. - func state(_ reading: Reading) { - objc_setAssociatedObject(self, &Self.readingKey, Statement(reading), .OBJC_ASSOCIATION_RETAIN_NONATOMIC) - } -} - - /// TEST-ONLY. Builds HealthKit samples the way the store hands them back: with a chosen UUID, an -/// attributable `HKSourceRevision`, and (for the series classes HealthKit offers no synthetic -/// initializer for) chosen dates, device and metadata. The content corpus also restates facts -/// HealthKit refuses when it creates a sample, and states ECG readings and voltages. +/// attributable `HKSourceRevision`, and (for the classes HealthKit offers no synthetic initializer for, or +/// for facts it refuses at creation) chosen dates, device, metadata and payload. /// /// HealthKit's public factories mint a fresh UUID and attribute every sample to the running /// process, so no test can otherwise pin a graph whose identities derive from the UUID, or one that /// carries writer and writer-host Device entries. The helper writes HealthKit's private ivars /// through key-value coding (`_UUID`, `_sourceRevision`, ...); such a sample behaves like a fetched -/// one, including through an `NSKeyedArchiver` round trip. `StoredSampleFixturesTests` fails, and -/// never skips, the moment HealthKit stops honoring a key, so a silent regression into -/// process-attributed samples cannot hide behind green goldens. +/// one, including through an `NSKeyedArchiver` round trip. +/// +/// Only this type touches private storage, and only the ivars its key table declares for each class: +/// ``instance(of:stating:)``, ``restate(_:with:)`` and ``read(_:of:)`` refuse any other key, and +/// `StoredSampleFixturesTests` fails, and never skips, the moment HealthKit stops declaring one, so a silent +/// regression into process-attributed samples cannot hide behind green goldens. The per-class builders the +/// content corpus uses live in `StoredSampleFixtures+Corpus.swift`. /// /// Nothing here may be used outside the test target. enum StoredSampleFixtures { @@ -82,37 +37,47 @@ enum StoredSampleFixtures { /// sample built in-process reports when nothing attributes it. static let unattributed = Writer(name: "", bundleIdentifier: "", version: nil, productType: nil) + /// The source's display name. var name: String + /// The source's bundle identifier. var bundleIdentifier: String + /// The revision's version, as the writing application stated it. var version: String? + /// The model of the device the writer ran on. var productType: String? + /// The operating system the writer ran on. var operatingSystemVersion = OperatingSystemVersion(majorVersion: 26, minorVersion: 1, patchVersion: 0) } - /// The facts of a sample whose class has no public initializer (`HKHeartbeatSeriesSample`, - /// `HKElectrocardiogram`, `HKWorkoutRoute`). - struct SeriesShape: Sendable { + /// Every fact a stored sample states besides its payload: its UUID, interval, device, metadata and writer. + /// + /// ``seriesSample(_:sampleType:facts:)`` builds a bare sample carrying exactly these facts, and + /// ``restated(_:facts:)`` states them on a built sample in place of what its initializer stated. + struct SampleFacts: Sendable { + /// The UUID the store gave the sample. var uuid: UUID + /// When the sample starts. var start: Date + /// When the sample ends; any instant, also one before `start`. var end: Date + /// The device the sample names. var device: HKDevice? + /// The metadata the sample carries, nil for none. var metadata: [String: any Sendable]? // swiftlint:disable:this discouraged_optional_collection + /// The source revision the sample is attributed to. var writer: Writer } - #if !os(watchOS) - /// The FHIR resource a provider issued, as an `HKClinicalRecord` carries it. - struct ClinicalResource { - var version: HKFHIRVersion - var type: HKFHIRResourceType - var identifier: String - var data: Data - } - #endif - + /// HealthKit no longer keeps a fact where the fixtures put it. enum FixtureError: Error, CustomStringConvertible { + /// HealthKit refused to allocate a bare instance of the class. case classNotConstructible(String) + /// The class no longer declares, or reads back, the private key. case keyNotHonored(key: String, class: String) + /// A fixture asked for a key the key table does not declare for the class. + case keyNotDeclared(key: String, class: String) + /// The unit does not measure the quantity type, so HealthKit would raise instead of converting. + case incompatibleUnit(unit: String, type: String) var description: String { switch self { @@ -120,21 +85,48 @@ enum StoredSampleFixtures { "HealthKit refused to allocate a bare \(name); the stored-sample fixtures need a new strategy" case let .keyNotHonored(key, name): "\(name) no longer reads back the value written to '\(key)'; the stored-sample fixtures need a new strategy" + case let .keyNotDeclared(key, name): + "the stored-sample fixtures declare no private key '\(key)' for \(name); add it to the key table first" + case let .incompatibleUnit(unit, type): + "\(unit) does not measure \(type)" } } } - private static let objectKeys = ["UUID", "sourceRevision", "device", "metadata"] - private static let sampleKeys = ["sampleType", "startTimestamp", "endTimestamp"] + /// Every private ivar the fixtures write or read, by the HealthKit class that declares it (without the leading + /// underscore); a key is honored on that class and its subclasses, and nowhere else. + private static let privateKeys: [(className: String, keys: [String])] = { + var table: [(className: String, keys: [String])] = [ + ("HKObject", ["UUID", "sourceRevision", "device", "metadata"]), + ("HKSample", ["sampleType", "startTimestamp", "endTimestamp"]), + ("HKSource", ["name", "bundleIdentifier"]), + ("HKQuantitySample", ["quantity", "count"]), + ("HKCategorySample", ["value"]), + ("HKCorrelation", ["objects"]), + ("HKWorkout", ["workoutActivityType", "duration", "primaryActivity"]), + ("HKWorkoutActivity", ["statisticsPerType"]), + ("HKStatistics", ["dataType", "sumQuantity", "averageQuantity", "minimumQuantity", "maximumQuantity"]), + ("HKStateOfMind", ["kind", "valence", "labels", "associations"]), + ("HKScoredAssessment", ["score"]), + ("HKElectrocardiogramVoltageMeasurement", ["timeSinceSampleStart", "leadIVoltage"]) + ] + #if !os(watchOS) + table += [ + ("HKCDADocumentSample", ["document"]), + ("HKCDADocument", ["internalDocumentData", "title"]), + ("HKClinicalRecord", ["FHIRResource"]), + ("HKFHIRResource", ["data", "FHIRVersion"]) + ] + #endif + return table + }() /// An `HKSource` naming the writing application; HealthKit itself only ever vends one for the running process. static func source(name: String, bundleIdentifier: String) throws -> HKSource { - let source = try allocate(HKSource.self) - try write(name, to: "name", of: source) - try write(bundleIdentifier, to: "bundleIdentifier", of: source) - return unsafeDowncast(source, to: HKSource.self) + try instance(of: HKSource.self, stating: ["name": name, "bundleIdentifier": bundleIdentifier]) } + /// The source revision a stored sample attributed to `writer` carries. static func sourceRevision(_ writer: Writer) throws -> HKSourceRevision { HKSourceRevision( source: try source(name: writer.name, bundleIdentifier: writer.bundleIdentifier), @@ -162,136 +154,97 @@ enum StoredSampleFixtures { /// `sample` carrying exactly `metadata`, written past HealthKit's initializer, which raises an Objective-C exception /// for a value it refuses (a half sync pair, a negative or textual sync version) instead of returning one. static func withMetadata(_ sample: Sample, _ metadata: [String: Any]) throws -> Sample { - try write(metadata as NSDictionary, to: "metadata", of: sample) + try restate(sample, with: ["metadata": metadata as NSDictionary]) guard (sample.metadata ?? [:]).keys.sorted() == metadata.keys.sorted() else { throw FixtureError.keyNotHonored(key: "metadata", class: String(describing: type(of: sample))) } return sample } - /// A bare instance of a sample class without a public initializer, carrying exactly `shape`. - static func seriesSample(_ type: Sample.Type, sampleType: HKSampleType, shape: SeriesShape) throws -> Sample { - let object = try allocate(type) - try write(sampleType, to: "sampleType", of: object) - let sample = try restated(unsafeDowncast(object, to: type), shape: shape) + /// A bare instance of a sample class without a public initializer, carrying exactly `facts`. + static func seriesSample(_ type: Sample.Type, sampleType: HKSampleType, facts: SampleFacts) throws -> Sample { + let sample = try restated(try instance(of: type, stating: ["sampleType": sampleType]), facts: facts) guard sample.sampleType == sampleType else { throw FixtureError.keyNotHonored(key: "sampleType", class: String(describing: type)) } return sample } - /// `sample` carrying exactly `shape`'s facts in place of the ones its initializer stated. + /// `sample` carrying exactly `facts` in place of the ones its initializer stated. /// /// HealthKit validates a sample only when it creates one, so a fact it refuses there (a reversed interval, /// a metadata value of the wrong type, an instant after 4000) can be stated only afterwards, as here. - static func restated(_ sample: Sample, shape: SeriesShape) throws -> Sample { - try write(NSNumber(value: shape.start.timeIntervalSinceReferenceDate), to: "startTimestamp", of: sample) - try write(NSNumber(value: shape.end.timeIntervalSinceReferenceDate), to: "endTimestamp", of: sample) - try write(shape.device, to: "device", of: sample) - try write(shape.metadata, to: "metadata", of: sample) - let stored = try stored(sample, uuid: shape.uuid, writer: shape.writer) + static func restated(_ sample: Sample, facts: SampleFacts) throws -> Sample { + try write(NSNumber(value: facts.start.timeIntervalSinceReferenceDate), to: "startTimestamp", of: sample) + try write(NSNumber(value: facts.end.timeIntervalSinceReferenceDate), to: "endTimestamp", of: sample) + try write(facts.device, to: "device", of: sample) + try write(facts.metadata, to: "metadata", of: sample) + let stored = try stored(sample, uuid: facts.uuid, writer: facts.writer) let name = String(describing: type(of: sample)) - guard stored.startDate == shape.start, stored.endDate == shape.end else { + guard stored.startDate == facts.start, stored.endDate == facts.end else { throw FixtureError.keyNotHonored(key: "startTimestamp/endTimestamp", class: name) } - guard stored.device == shape.device, (stored.metadata ?? [:]).keys.sorted() == (shape.metadata ?? [:]).keys.sorted() else { + guard stored.device == facts.device, (stored.metadata ?? [:]).keys.sorted() == (facts.metadata ?? [:]).keys.sorted() else { throw FixtureError.keyNotHonored(key: "device/metadata", class: name) } return stored } - /// An ECG carrying exactly `shape` and stating `reading` as HealthKit would report it. - static func electrocardiogram(shape: SeriesShape, reading: StoredElectrocardiogram.Reading) throws -> HKElectrocardiogram { - let ecg = try seriesSample(StoredElectrocardiogram.self, sampleType: HKObjectType.electrocardiogramType(), shape: shape) - ecg.state(reading) - return ecg - } - - /// One voltage of an ECG's lead, or a measurement that states no lead voltage at all. - static func voltageMeasurement(offset: TimeInterval, millivolts: Double?) throws -> HKElectrocardiogram.VoltageMeasurement { - let object = try allocate(HKElectrocardiogram.VoltageMeasurement.self) - try write(NSNumber(value: offset), to: "timeSinceSampleStart", of: object) - try write(millivolts.map { HKQuantity(unit: .voltUnit(with: .milli), doubleValue: $0) }, to: "leadIVoltage", of: object) - let measurement = unsafeDowncast(object, to: HKElectrocardiogram.VoltageMeasurement.self) - guard measurement.timeSinceSampleStart.bitPattern == offset.bitPattern, - (measurement.quantity(for: .appleWatchSimilarToLeadI) == nil) == (millivolts == nil) else { - throw FixtureError.keyNotHonored(key: "timeSinceSampleStart/leadIVoltage", class: "HKElectrocardiogram.VoltageMeasurement") + /// Whether every class in the key table still exists and still declares every key, checked before a single + /// value is written. + static func privateStorageIsPresent() -> Bool { + privateKeys.allSatisfy { className, keys in + guard let declaring = NSClassFromString(className) else { + return false + } + return keys.allSatisfy { class_getInstanceVariable(declaring, "_\($0)") != nil } } - return measurement } - /// An `HKElectrocardiogram` reading `shape`'s facts, its classification, symptoms status and average heart rate. - /// Its voltages are HealthKit's private storage and stay unset, so it reports no measurement count and no sampling - /// frequency. HealthKit keeps the classification under a private numbering: `reading` names that number and the - /// public classification it must read back as, and the fixture fails unless every value reads back. - static func electrocardiogram( - shape: SeriesShape, - reading: (privateClassification: Int, classification: HKElectrocardiogram.Classification), - symptomsStatus: HKElectrocardiogram.SymptomsStatus, - averageHeartRate: HKQuantity - ) throws -> HKElectrocardiogram { - let ecg = try seriesSample(HKElectrocardiogram.self, sampleType: HKObjectType.electrocardiogramType(), shape: shape) - try write(NSNumber(value: reading.privateClassification), to: "privateClassification", of: ecg) - try write(NSNumber(value: symptomsStatus.rawValue), to: "symptomsStatus", of: ecg) - try write(averageHeartRate, to: "averageHeartRate", of: ecg) - guard ecg.classification == reading.classification, - ecg.symptomsStatus == symptomsStatus, - ecg.averageHeartRate == averageHeartRate else { - throw FixtureError.keyNotHonored(key: "privateClassification/symptomsStatus/averageHeartRate", class: String(describing: HKElectrocardiogram.self)) + /// A bare instance of `type`, none of whose initializers ran, carrying `facts` in its private storage. + static func instance(of type: Object.Type, stating facts: KeyValuePairs) throws -> Object { + guard let object = class_createInstance(type, 0) as? NSObject else { + throw FixtureError.classNotConstructible(String(describing: type)) } - return ecg + try restate(object, with: facts) + return unsafeDowncast(object, to: type) } - #if !os(watchOS) - /// An `HKClinicalRecord` carrying `resource` as the provider's FHIR resource, the way a fetched record carries it; - /// HealthKit offers no initializer for either class. Fails unless the record reads every value back. - static func clinicalRecord( - _ type: HKClinicalTypeIdentifier, - shape: SeriesShape, - displayName: String, - resource: ClinicalResource - ) throws -> HKClinicalRecord { - let fhirResource = try allocate(HKFHIRResource.self) - try write(resource.version, to: "FHIRVersion", of: fhirResource) - try write(resource.type.rawValue, to: "resourceType", of: fhirResource) - try write(resource.identifier, to: "identifier", of: fhirResource) - try write(resource.data, to: "data", of: fhirResource) - let record = try seriesSample(HKClinicalRecord.self, sampleType: HKClinicalType(type), shape: shape) - try write(displayName, to: "displayName", of: record) - try write(fhirResource, to: "FHIRResource", of: record) - guard record.displayName == displayName, - record.fhirResource?.data == resource.data, - record.fhirResource?.resourceType == resource.type, - record.fhirResource?.fhirVersion.fhirRelease == resource.version.fhirRelease else { - throw FixtureError.keyNotHonored(key: "displayName/FHIRResource", class: String(describing: HKClinicalRecord.self)) + /// States `facts` in `object`'s private storage, each under a key the key table declares for its class. + static func restate(_ object: NSObject, with facts: KeyValuePairs) throws { + for (key, value) in facts { + try write(value, to: key, of: object) } - return record } - #endif - /// Whether every private ivar the fixtures write still exists, checked before a single value is written. - static func privateStorageIsPresent() -> Bool { - (objectKeys.allSatisfy { class_getInstanceVariable(HKObject.self, "_\($0)") != nil }) - && (sampleKeys.allSatisfy { class_getInstanceVariable(HKSample.self, "_\($0)") != nil }) - && ["name", "bundleIdentifier"].allSatisfy { class_getInstanceVariable(HKSource.self, "_\($0)") != nil } + /// One private ivar's value, read through key-value coding only while the class still declares the key, so a + /// HealthKit that dropped it fails with ``FixtureError/keyNotHonored(key:class:)`` instead of raising. + static func read(_ key: String, of object: NSObject) throws -> Any? { + try requireDeclared(key, on: object) + return object.value(forKey: key) } - /// A bare instance of `type`, none of whose initializers ran. - static func allocate(_ type: AnyClass) throws -> NSObject { - guard let object = class_createInstance(type, 0) as? NSObject else { - throw FixtureError.classNotConstructible(String(describing: type)) - } - return object + /// Writes one private ivar through key-value coding, failing when the key table or the class lacks it. + private static func write(_ value: Any?, to key: String, of object: NSObject) throws { + try requireDeclared(key, on: object) + object.setValue(value, forKey: key) } - /// Writes one private ivar through key-value coding, failing when the class no longer has it. - static func write(_ value: Any?, to key: String, of object: NSObject) throws { + /// Fails unless the key table declares `key` for a class `object` is a kind of, and the class still has it. + private static func requireDeclared(_ key: String, on object: NSObject) throws { + let name = String(describing: type(of: object)) + let declared = privateKeys.contains { className, keys in + keys.contains(key) && NSClassFromString(className).map { object.isKind(of: $0) } == true + } + guard declared else { + throw FixtureError.keyNotDeclared(key: key, class: name) + } guard class_getInstanceVariable(type(of: object), "_\(key)") != nil else { - throw FixtureError.keyNotHonored(key: key, class: String(describing: type(of: object))) + throw FixtureError.keyNotHonored(key: key, class: name) } - object.setValue(value, forKey: key) } + /// Fails unless `sample` reports the UUID and, when given, the writer that were written. private static func verify(_ sample: HKSample, uuid: UUID, writer: Writer?) throws { let name = String(describing: type(of: sample)) guard sample.uuid == uuid else { diff --git a/Tests/GroveHealthKitFHIRTests/StoredSampleFixturesTests.swift b/Tests/GroveHealthKitFHIRTests/StoredSampleFixturesTests.swift index 16e84ad8f..020ee4347 100644 --- a/Tests/GroveHealthKitFHIRTests/StoredSampleFixturesTests.swift +++ b/Tests/GroveHealthKitFHIRTests/StoredSampleFixturesTests.swift @@ -23,7 +23,7 @@ struct StoredSampleFixturesTests { private static let uuid = GoldenFixtures.uuid(0xF0) private static let writer = GoldenFixtures.foreignWriter - private static func expectStored(_ sample: HKSample, sourceLocation: SourceLocation = #_sourceLocation) throws { + private static func expectStored(_ sample: HKSample, uuid: UUID = uuid, sourceLocation: SourceLocation = #_sourceLocation) throws { #expect(sample.uuid == uuid, sourceLocation: sourceLocation) let revision = sample.sourceRevision #expect(revision.source.name == writer.name, sourceLocation: sourceLocation) @@ -46,6 +46,94 @@ struct StoredSampleFixturesTests { #expect(StoredSampleFixtures.privateStorageIsPresent()) } + @Test("A key the key table does not declare for a class is refused before anything is written") + func undeclaredKeysAreRefused() throws { + let sample = try GoldenFixtures.heartRate(uuid: Self.uuid) + #expect(throws: StoredSampleFixtures.FixtureError.self) { + try StoredSampleFixtures.restate(sample, with: ["value": NSNumber(value: 1)]) + } + #expect(throws: StoredSampleFixtures.FixtureError.self) { + try StoredSampleFixtures.read("freezeState", of: sample) + } + #expect(sample.quantity.doubleValue(for: GoldenFixtures.beatsPerMinute) == 72) + } + + @Test("A restated sample states facts HealthKit refuses at creation: a reversed interval, mistyped metadata, a far-future instant") + func restatedSamplesStateRefusedFacts() throws { + var facts = GoldenCase.seriesFacts(uuid: 0xF1, duration: 30) + facts.end = facts.start.addingTimeInterval(-30) + facts.metadata = [HKMetadataKeyTimeZone: 42, HKMetadataKeyWasUserEntered: "yes"] + let reversed = try StoredSampleFixtures.restated(try GoldenFixtures.heartRate(uuid: Self.uuid), facts: facts) + #expect(reversed.uuid == GoldenFixtures.uuid(0xF1)) + #expect(reversed.endDate < reversed.startDate) + #expect(reversed.metadata?[HKMetadataKeyTimeZone] as? Int == 42) + #expect(reversed.metadata?[HKMetadataKeyWasUserEntered] as? String == "yes") + try Self.expectStored(reversed, uuid: GoldenFixtures.uuid(0xF1)) + facts.start = Date(timeIntervalSince1970: 253_402_300_800) + facts.end = facts.start + let farFuture = try StoredSampleFixtures.restated(try GoldenFixtures.heartRate(uuid: Self.uuid), facts: facts) + #expect(farFuture.startDate.timeIntervalSince1970 == 253_402_300_800) + } + + @Test("A stored ECG states its whole reading, and its voltages state their offsets and leads") + func electrocardiogramsStateTheirReading() throws { + let reading = StoredElectrocardiogram.Reading( + classification: try #require(HKElectrocardiogram.Classification(rawValue: 99)), + symptomsStatus: .present, + numberOfVoltageMeasurements: 3, + averageHeartRate: HKQuantity(unit: GoldenFixtures.beatsPerMinute, doubleValue: 72.5), + samplingFrequency: nil + ) + let ecg = try StoredSampleFixtures.electrocardiogram(facts: GoldenCase.seriesFacts(uuid: 0xF2, duration: 30), reading: reading) + #expect(ecg.classification.rawValue == 99) + #expect(ecg.symptomsStatus == .present) + #expect(ecg.numberOfVoltageMeasurements == 3) + #expect(ecg.averageHeartRate?.doubleValue(for: GoldenFixtures.beatsPerMinute) == 72.5) + #expect(ecg.samplingFrequency == nil) + try Self.expectStored(ecg, uuid: GoldenFixtures.uuid(0xF2)) + #expect(HealthKitSourceType(ecg) == .electrocardiogram) + + let voltage = try StoredSampleFixtures.voltageMeasurement(offset: 0.252, millivolts: -0.125) + #expect(voltage.timeSinceSampleStart == 0.252) + #expect(voltage.quantity(for: .appleWatchSimilarToLeadI)?.doubleValue(for: .voltUnit(with: .milli)) == -0.125) + let leadless = try StoredSampleFixtures.voltageMeasurement(offset: .nan, millivolts: nil) + #expect(leadless.timeSinceSampleStart.isNaN) + #expect(leadless.quantity(for: .appleWatchSimilarToLeadI) == nil) + } + + @Test("Each corpus builder states a payload HealthKit refuses at creation, and the sample's facts") + func corpusBuildersStateTheirPayloads() throws { + let facts = GoldenCase.seriesFacts(uuid: 0xF3, duration: 60) + let steps = try StoredSampleFixtures.quantitySample(HKQuantityType(.stepCount), value: -1, unit: .count(), facts: facts) + #expect(steps.quantity.doubleValue(for: .count()) == -1) + #expect(steps is HKCumulativeQuantitySample) + let sleep = try StoredSampleFixtures.categorySample(HKCategoryType(.sleepAnalysis), value: 99, facts: facts) + #expect(sleep.value == 99) + let systolic = try StoredSampleFixtures.quantitySample(HKQuantityType(.bloodPressureSystolic), value: 120, unit: .millimeterOfMercury(), facts: facts) + let pressure = try StoredSampleFixtures.correlation(HKCorrelationType(.bloodPressure), objects: [systolic], facts: facts) + #expect(pressure.objects.map(\.sampleType) == [HKQuantityType(.bloodPressureSystolic)]) + let distance = StoredSampleFixtures.WorkoutStatistic( + type: HKQuantityType(.distanceWalkingRunning), unit: .meterUnit(with: .kilo), sum: 10.5, average: nil, minimum: nil, maximum: nil + ) + let workout = try StoredSampleFixtures.workout(activity: 9_999, duration: .nan, statistics: [distance], facts: facts) + #expect(workout.workoutActivityType.rawValue == 9_999) + #expect(workout.duration.isNaN) + let meters = try #require(workout.statistics(for: HKQuantityType(.distanceWalkingRunning))?.sumQuantity()?.doubleValue(for: .meter())) + #expect(abs(meters - 10_500) < 1e-6) + let reflection = try StoredSampleFixtures.stateOfMind(kind: 99, valence: 0.25, labels: [999], associations: [], facts: facts) + #expect(reflection.kind.rawValue == 99) + #expect(reflection.labels.map(\.rawValue) == [999]) + let assessment = try #require(try StoredSampleFixtures.scoredAssessment(.GAD7, score: 99, facts: facts)) + #expect(assessment.score == 99) + for sample in [steps, sleep, pressure, workout, reflection, assessment] as [HKSample] { + try Self.expectStored(sample, uuid: GoldenFixtures.uuid(0xF3)) + #expect(sample.endDate == facts.end) + } + #expect(throws: StoredSampleFixtures.FixtureError.self) { + try StoredSampleFixtures.quantitySample(HKQuantityType(.stepCount), value: 1, unit: .meter(), facts: facts) + } + } + @Test("A sample from a public initializer takes the chosen UUID and writer, and keeps them through an archive") func publicInitializerSamplesAreStorable() throws { let sample = try GoldenFixtures.heartRate(uuid: Self.uuid, device: GoldenFixtures.watch, writer: Self.writer) @@ -69,17 +157,17 @@ struct StoredSampleFixturesTests { #expect(workout.workoutEvents?.count == 12) } - @Test("A series class without a public initializer takes every fact of its shape, and keeps them through an archive") + @Test("A series class without a public initializer takes every one of its facts, and keeps them through an archive") func seriesSamplesAreConstructible() throws { - let shape = GoldenCase.seriesShape(uuid: 0xF0, duration: 30) - let series = try StoredSampleFixtures.seriesSample(HKHeartbeatSeriesSample.self, sampleType: HKSeriesType.heartbeat(), shape: shape) - let ecg = try StoredSampleFixtures.seriesSample(HKElectrocardiogram.self, sampleType: HKObjectType.electrocardiogramType(), shape: shape) - let route = try StoredSampleFixtures.seriesSample(HKWorkoutRoute.self, sampleType: HKSeriesType.workoutRoute(), shape: shape) + let facts = GoldenCase.seriesFacts(uuid: 0xF0, duration: 30) + let series = try StoredSampleFixtures.seriesSample(HKHeartbeatSeriesSample.self, sampleType: HKSeriesType.heartbeat(), facts: facts) + let ecg = try StoredSampleFixtures.seriesSample(HKElectrocardiogram.self, sampleType: HKObjectType.electrocardiogramType(), facts: facts) + let route = try StoredSampleFixtures.seriesSample(HKWorkoutRoute.self, sampleType: HKSeriesType.workoutRoute(), facts: facts) for sample in [series, ecg, route] as [HKSample] { try Self.expectStored(sample) - #expect(sample.startDate == shape.start) - #expect(sample.endDate == shape.end) - #expect(sample.device == shape.device) + #expect(sample.startDate == facts.start) + #expect(sample.endDate == facts.end) + #expect(sample.device == facts.device) #expect(sample.metadata?[HKMetadataKeyTimeZone] as? String == GoldenFixtures.timeZone) } #expect(series.sampleType == HKSeriesType.heartbeat()) @@ -91,7 +179,7 @@ struct StoredSampleFixturesTests { let restored = try Self.archived(series, as: HKHeartbeatSeriesSample.self) try Self.expectStored(restored) - #expect(restored.startDate == shape.start) + #expect(restored.startDate == facts.start) #expect(restored.sampleType == HKSeriesType.heartbeat()) } diff --git a/Tests/GroveHealthKitFHIRTests/TokenDiff.swift b/Tests/GroveHealthKitFHIRTests/TokenDiff.swift new file mode 100644 index 000000000..55263bba3 --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/TokenDiff.swift @@ -0,0 +1,211 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +@testable import GroveFHIRContract + + +/// Compares two token trees the way the exchange protocol does: member order is free, array order and number +/// lexemes are not. The goldens and the content corpus report drift through it. +enum TokenDiff { + /// One place where two token trees differ, with what each states there; nil where one states nothing. + struct Difference: CustomStringConvertible { + /// Where the trees differ, as `$.member[index]...`. + let path: String + /// The checked-in tree's value at `path`. + let expected: LosslessJSONValue? + /// The actual tree's value at `path`. + let actual: LosslessJSONValue? + /// What differs when the values alone do not say it: a member name that differs only in its Unicode scalars. + var detail: String? + + var description: String { + if let detail { + return "\(path): \(detail)" + } + return switch (expected, actual) { + case let (expected?, actual?): + "\(path): golden \(TokenDiff.summary(expected)), actual \(TokenDiff.summary(actual))" + case let (nil, actual?): + "\(path): golden has no such member, actual is \(TokenDiff.summary(actual))" + case let (expected?, nil): + "\(path): missing, golden has \(TokenDiff.summary(expected))" + case (nil, nil): + path + } + } + + /// The change as a corpus change report states it: both values in full, `(absent)` for a missing one. + var change: String { + "\(path): \(expected?.canonicalText ?? "(absent)") -> \(actual?.canonicalText ?? "(absent)")" + } + } + + /// The first path where two token trees differ, or nil when they are equal. + static func firstDifference(expected: LosslessJSONValue, actual: LosslessJSONValue) -> String? { + differences(expected: expected, actual: actual, limit: 1).first?.description + } + + /// Every place, up to `limit`, where two token trees differ: objects and arrays are walked into, so each + /// difference is a leaf, a member or element only one tree has, or a value whose kind differs. + static func differences(expected: LosslessJSONValue, actual: LosslessJSONValue, limit: Int = .max) -> [Difference] { + var found: [Difference] = [] + collect(expected: expected, actual: actual, at: "$", limit: limit, into: &found) + return found + } + + /// Appends every difference below `path`, stopping once `limit` are found. + private static func collect( + expected: LosslessJSONValue, + actual: LosslessJSONValue, + at path: String, + limit: Int, + into found: inout [Difference] + ) { + switch (expected, actual) { + case let (.object(lhs), .object(rhs)): + let before = found.count + for key in Set(lhs.keys).union(rhs.keys).sorted() where found.count < limit { + collectPresent(expected: lhs[key], actual: rhs[key], at: "\(path).\(key)", limit: limit, into: &found) + } + // Every value matched under a dictionary lookup, which finds canonically equivalent names alike. + if found.count == before, found.count < limit, expected != actual { + found.append(Difference(path: path, expected: expected, actual: actual, detail: "a member name differs in its Unicode scalars")) + } + case let (.array(lhs), .array(rhs)): + for index in 0.. String { + switch value { + case .object(let members): "object(\(members.count) members)" + case .array(let elements): "array(\(elements.count))" + case .string(let text): "\"" + text.unicodeScalars.map { $0.isASCII ? String($0) : "\\u{\(String($0.value, radix: 16))}" }.joined() + "\"" + case .number(let lexeme): lexeme + case .boolean(let flag): "\(flag)" + case .null: "null" + } + } +} + + +extension LosslessJSONValue { + /// The elements of an array, or nil for any other kind. + var elements: [LosslessJSONValue]? { // swiftlint:disable:this discouraged_optional_collection + guard case .array(let elements) = self else { + return nil + } + return elements + } + + /// The text of a string, or nil for any other kind. + var text: String? { + guard case .string(let text) = self else { + return nil + } + return text + } + + /// Compact JSON with members sorted by key and every number lexeme kept as read: two values print alike exactly + /// when their tokens are equal and their strings hold the same scalars, so a corpus line diffs by content. + var canonicalText: String { + var text = "" + append(to: &text) + return text + } + + /// Appends `string` as a JSON string literal. + private static func append(_ string: String, to text: inout String) { + text.append("\"") + for scalar in string.unicodeScalars { + switch scalar { + case "\"": text.append("\\\"") + case "\\": text.append("\\\\") + case "\n": text.append("\\n") + case "\r": text.append("\\r") + case "\t": text.append("\\t") + case _ where scalar.value < 0x20: text.append(String(format: "\\u%04x", scalar.value)) + default: text.unicodeScalars.append(scalar) + } + } + text.append("\"") + } + + /// Appends the value's canonical text. + private func append(to text: inout String) { + switch self { + case .object(let members): + text.append("{") + for (index, key) in members.keys.sorted().enumerated() { + text.append(index == 0 ? "" : ",") + Self.append(key, to: &text) + text.append(":") + members[key]?.append(to: &text) + } + text.append("}") + case .array(let elements): + text.append("[") + for (index, element) in elements.enumerated() { + text.append(index == 0 ? "" : ",") + element.append(to: &text) + } + text.append("]") + case .string(let string): + Self.append(string, to: &text) + case .number(let lexeme): + text.append(lexeme) + case .boolean(let flag): + text.append(flag ? "true" : "false") + case .null: + text.append("null") + } + } + + /// The value of an object's member, or nil when there is none or the value is no object. + subscript(member: String) -> LosslessJSONValue? { + guard case .object(let members) = self else { + return nil + } + return members[member] + } +} + +#endif From 7e164bb14bc674aa255fff3daaf3cbe0a7807131 Mon Sep 17 00:00:00 2001 From: Lukas Kollmer Date: Sat, 3 Oct 2026 22:12:13 +0200 Subject: [PATCH 054/220] Widen the HealthKit Content Corpus to What the M0 Checks Found MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to 29cbbfab (track 3, M0) and 0f3019ff: the coverage gaps the mutation acceptance check and the output-preservation review found (brief sections A and B), and how inputs state an Observation and an invisible character (C8, C10). Recorded from the current builders. Tests only; no file under Sources/ changes, no golden changes, and no output value of an existing corpus line changes. Added vectors (314; content-corpus.jsonl 3,003 -> 3,317 lines, 3,993,971 -> 4,716,945 bytes, sha256 7f7d00fc7252b199...): - time/ (56): every time record also at 1960-01-01T12:00:00Z (before 1970 at a whole-hour offset) without a zone and in Los Angeles, and every instant also in UTC by name. Among them the two of A2: heart rate at 1960 in Los Angeles (1960-01-01T04:00:00-08:00 with its timezone extension) and at 1500 in UTC (1500-01-01T00:00:00Z with its timezone extension). - electrocardiogram/time/ (6, A3 and B12): the row ECG starting at 15:30:59.75 local (effectivePeriod 15:31:00-07:00 to 15:31:00.006-07:00), at local year 10000 (refused, invalidSourcePeriod), in 1500 in Los Angeles and in UTC, and in both occurrences of the repeated 2026 DST hour (-07:00, -08:00). - electrocardiogram/precedence/ (13, B1): one two-fault vector per adjacent pair of the ECG checks; each reports the first: zone before missing lead, missing lead before count, count before offsets, offsets before period (invalidOffset 3 before nonUniformOffset 2), period before frequency, frequency before finite voltages, voltages before symptom contexts, symptom contexts before symptom validation, symptom validation before the source period, symptoms status before the source period (the status is checked with the symptoms) and before classification, classification before algorithm version, algorithm version before average heart rate. - precedence/ (3, B1 and B3): a year-10000 instant before a category value and before a heart-rate motion context (both report the effective failure), and an unknown zone before an assessment's year-10000 instant. The two M0 vectors B3 names stay as recorded. - quantity/HKQuantityTypeIdentifierInsulinDelivery/basal/ (9, B4): the insulin sweep again with HKMetadataKeyInsulinDeliveryReason basal, so its values reach the value check. - quantity//alternate-unit (101) and workout/statistics/distance-km, energy-kj (2) (B9): every unit-bound quantity row with another unit of its dimension (lb, oz, g, mg, ft, in, km/hr, count/s, hr, s, degF, kJ, kW, mL, fl_oz_us, g/L, S, L/min.kg, kJ/hr.kg, mL/min, count) at its admitted value, so the reading converts; rows bound to count, IU, dB SPL or the effort score have no other unit. No molar unit is used: HealthKit's unit string rounds the molar mass, so mmol/L cannot be restated exactly (it drifted by one ulp across processes). - retraction/native-identifier/ (6, B8): heart rate, blood pressure, workout, ECG, heartbeat series and a lab result with the store's UUID disclosed. - round-trip/ (118, B2): every time/ and metadata/ heart-rate and body-mass vector before 4000 is converted, and each Observation, decoded from the wire bytes, is projected back to an HKSample: the timezone extension, +05:45 and -02:30 offsets, millisecond ties, minted sync identifiers, manual entry and writer versions as the reverse projection reads them. Richer rendering (1,592 existing lines gain members; no existing value changes): - B5: every graph renders "envelope": its entries' resource types in Bundle order, each Provenance target as the index of the entry it names, and a SHA-256 digest of the Bundle's own members and every non-output entry (1,350 convert lines). - B7: a reverse-projected sample renders "metadataTypes" (string, integer, double, boolean) beside the NSNumber text (38 reverse lines, one also in its correlation members). - B8: a retraction target renders its identifier system and its native record identifier, null under the default policy (204 lines). Restated inputs (213, exactly these; regenerated with GROVE_CONTENT_CORPUS_ALLOW_RESTATED_INPUTS="reverse/,clinical/undecodable/ byte-order-mark"): - C8, C10: a reverse projection is its own input, reverse(observation:), with the Observation nested as JSON (numbers as exact decimals) instead of an escaped string under catalog(.reverse): the 212 reverse/ lines, each the same Observation. - C8: inputs print invisible scalars escaped, so clinical/undecodable/byte-order-mark states its payload's byte order mark as  instead of carrying a raw U+FEFF. Exporter pass (B10): ContentCorpusExporterTests exports every convert vector through HealthKitFHIRExporter with the options its converter context states (gateway role and a study for linked vectors, authorized routes) and a sequencer ledger seeded with the test producer instance at sequence 300, so the exporter mints the facade's events; outputs, envelopes (digests included), refusals and omissions must equal the line, warnings by registered code (the exporter reports diagnostics only). Three ECG vectors whose symptom contexts are miscounted on purpose cannot be stated to the exporter and are skipped. Correction to 29cbbfab: its deviation said converted Observations are not round-tripped because HealthKit raises for instants after 4000 and for types with a minimum duration. The second reason was wrong: none of the 29 reverse-projected quantity types is minimum-duration restricted, and a Period contract is refused before any sample is created. Only the 4000 horizon applies; the recorder refuses a round trip after 4000 or of a minimum-duration type instead of letting HealthKit raise. What the new vectors pin (production behavior, unchanged here): - ECG timing at a sub-minute zone offset: electrocardiogram/time/ pre-reform-1500 (Los Angeles local mean time, -07:52:58) prints 1499-12-31T16:07:02.25-07:52, an offset truncated to minutes, so the lexeme names an instant 58 s off; the mobile kernel refuses such offsets. - Pre-1582 round trips shift: 1500-01-01T00:00:00Z projects back to -14830992000 (9 days later) and 0001-01-01T00:00:00Z to -62135769600 (2 days earlier), the FX-proleptic-reverse defect. - A year-10000 effective instant on the dateTime path is reported as mobile-input.value-shape-invalid at HKSample.value, as a NaN value is. Verification: a script over the old and new corpus checked that every old id remains in order, every old output value is unchanged (new lines and members only), and the only changed inputs are the 213 above, each reverse input parsing to the same JSON. Two regenerations in separate processes are byte identical, and content-corpus.changes.txt reports 314 added, 0 removed, 0 duplicated, 213 restated, 1,592 changed (members added). Mutation acceptance (brief section A), re-run on this commit with the M0 check's 11 mutants (mutate.py unchanged), each applied alone to Sources/, built, and run against ContentCorpusTests, ContentCorpusExporterTests and GoldenGraphTests; the unmutated control passes. Counts are failing corpus vectors (summed over the 8 shards); the exporter pass fails on the same convert vectors, and the goldens catch none: mutant site M0 now m1 notification value mapping CategoryValues values[value] 0 0 (*) m2 ECG atrialFibrillation code ECGCore classificationCode 1 1 m3 assessment score + 1 SourceValues fhirQuantity 10 10 m4 ECG symptoms status -> notSet ECGCore ecgSourceEvidence 32 40 m5a effective truncated (call) Observation applyEffective 12 36 m5b effective truncated (kernel) EffectiveTime mobileLexeme 24 54 m6 percent rounded to 0.1 Observation percent scaling 80 80 m7 named UTC printed +00:00 EffectiveTime lexeme 4 42 m8a tz extension dropped at +00:00 EffectiveTime dateTime 4 42 m8b tz extension dropped pre-1970 EffectiveTime dateTime 0 20 m9 ECG seconds without carry EffectiveTime exactDateTime 0 1 10 of 11 mutants now fail the corpus (M0: 8; the M0 column recounts the M0 check's own result bundles). m8b fails on 20 time vectors: each time record at 1960 in Los Angeles and at 1960, 1800, 1500 and year 1 in UTC; m9 fails on electrocardiogram/time/start-carries-into-minute (the mutant prints 15:30:60). (*) m1 stays equivalent today: walking-steadiness notifications are refused before the mapping, so it becomes catchable only with the approved walking-steadiness fix (FX-walking-steadiness). Gates: Gate 1 (macOS): 283 tests, 280 passed (694 test runs), 0 failed, 3 skipped (corpus regeneration and the two benchmark tests); all 42 goldens and outlines.json pass. SwiftLint strict (Sources/GroveFHIRContract, Sources/GroveHealthKitFHIR, Tests/GroveHealthKitFHIRTests) and reuse lint clean. Rebased onto 28f93119 (exchange-ledger fix round). The ledger is now keyed and transactional, so the corpus ledger is an in-memory storage seeded with the producer entry (the test producer instance, next sequence 300); every corpus ledger states that same instance, so each sequencer keeps its own hold registry. The ledger also numbers the new events of one call in the sorted order of their keys, which are digests, so an ECG export no longer numbers its symptoms in the record's order. The exporter pass therefore first reserves the record's request and then each symptom's, one call each, in the facade's order, and the export reuses those reservations; without that, electrocardiogram/symptoms/two-types exports its first symptom under another event than the facade's. As in the M0 commit, the three foreign-writer metadata/sync vectors fail here until the branch's corpus restatement. Rebased onto 48911aa0 (the exchange-ledger fix round's G3 and G1b): the exporter plans each input with what its policies resolve (HealthKitFHIRExporter.Plan(_:exporter:)), so the corpus's facade-order pre-reservation plans through the exporter itself and reserves exactly the requests, fingerprints included, its export then reuses. Co-Authored-By: Claude Opus 5.5 --- .../ContentCorpus/ContentCorpusCatalog.swift | 4 +- .../ContentCorpusExporterTests.swift | 168 + .../ContentCorpusGrid+Catalog.swift | 23 +- .../ContentCorpusGrid+Metadata.swift | 17 +- .../ContentCorpusGrid+Recordings.swift | 74 +- .../ContentCorpusGrid+Records.swift | 8 +- .../ContentCorpusGrid+Time.swift | 91 + .../ContentCorpus/ContentCorpusGrid.swift | 108 +- .../ContentCorpus/ContentCorpusInput.swift | 77 +- .../ContentCorpusRecorder+Projections.swift | 80 +- .../ContentCorpus/ContentCorpusRecorder.swift | 42 +- .../ContentCorpus/ContentCorpusStore.swift | 15 +- .../ContentCorpus/content-corpus.jsonl | 3848 +++++++++-------- Tests/GroveHealthKitFHIRTests/TokenDiff.swift | 21 +- 14 files changed, 2708 insertions(+), 1868 deletions(-) create mode 100644 Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusExporterTests.swift create mode 100644 Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Time.swift diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusCatalog.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusCatalog.swift index e52211eb6..f37d092bf 100644 --- a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusCatalog.swift +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusCatalog.swift @@ -16,7 +16,7 @@ import ModelsR4 /// Renders the public catalog surface the content layer publishes: inventory rows with their outputs and field -/// dispositions, the unit bindings, both unit lookups, and the reverse projection of Observations. +/// dispositions, the unit bindings, and both unit lookups. enum ContentCorpusCatalog { /// The tokens one catalog projection renders as. static func projection(_ projection: ContentCorpusProjection) throws -> LosslessJSONValue { @@ -38,8 +38,6 @@ enum ContentCorpusCatalog { "unitSpelling": unitText(HealthKitCatalog.unit(forUnitSpelling: spelling)) ])) })) - case .reverse(let observation): - ContentCorpusRecorder.reverse(try JSONDecoder().decode(Observation.self, from: Data(observation.utf8))) } } diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusExporterTests.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusExporterTests.swift new file mode 100644 index 000000000..9aad7700d --- /dev/null +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusExporterTests.swift @@ -0,0 +1,168 @@ +// +// This source file is part of the Grove open-source project +// +// SPDX-FileCopyrightText: 2026 Stanford University and the project authors (see CONTRIBUTORS.md) +// +// SPDX-License-Identifier: MIT +// + +#if canImport(HealthKit) + +import Foundation +@testable import GroveFHIRContract +@testable import GroveHealthKitFHIR +import HealthKit +import Testing + + +/// A sequencer ledger that starts where the corpus's events do: under the test context's producer instance, at +/// the corpus's sequence, so the exporter mints exactly the events the converter facade was handed. +private enum CorpusLedger { + /// A sequencer over an in-memory ledger whose producer entry hands out `nextSequence` under `producerInstance`. + /// + /// Every corpus ledger states the same producer instance, so their reservation handles are not unique across + /// ledgers; each sequencer therefore keeps its own hold registry instead of the process's shared one. + static func sequencer(producerInstance: UUID, nextSequence: UInt64) throws -> ExchangeEventSequencer { + let storage = ExchangeEventSequencer.InMemoryStorage() + let producer = try ProducerEntry(instance: producerInstance, next: nextSequence).encoded() + try storage.transaction { try $0.write(producer, for: LedgerKey.producer) } + return ExchangeEventSequencer(storage: storage, holds: HoldRegistry()) + } +} + + +/// The exporter renders the corpus: every convert vector, exported through `HealthKitFHIRExporter` with the options +/// its converter context states and under the same events, produces the outputs, envelope digests and refusals +/// its line pins. The exporter reports a warning as its registered diagnostic only, so warnings compare by code. +/// +/// This is where the corpus's port points lead: once the deprecated facade is gone, the recorder converts this way. +@Suite +struct ContentCorpusExporterTests { + /// The test context every corpus event is minted under. + private static let base = ExchangeEventContext.test() + + /// The tokens `source` exports to, warnings as codes; nil for a vector the exporter cannot state (an ECG whose + /// symptom contexts the caller miscounts) or whose record this platform does not have. + private static func exported(_ source: ContentCorpusSource) throws -> LosslessJSONValue? { + let record: HealthKitFHIRExporter.Record + do { + guard let built = try exporterRecord(source) else { + return nil + } + record = built + } catch ContentCorpusSamples.RebuildError.unavailableHere { + return nil + } + let exporter = try exporter(for: source) + try reserveFacadeEvents(of: record, through: exporter) + var exports: [HealthKitFHIRExporter.Export] = [] + _ = try exporter.export(records: [record], at: GoldenFixtures.conversionInstant) { exports.append($0) } + guard !exports.isEmpty else { + return .object(["omitted": .boolean(true)]) + } + if exports.count == 1, case .refused(let error) = exports[0].outcome { + return ContentCorpusRecorder.refusal(error) + } + let graphs = try exports.map { export in + guard let graph = export.graph else { + return LosslessJSONValue.string("unexpected outcome \(export.outcome)") + } + return try ContentCorpusRecorder.graph(graph, warnings: export.warnings.map(\.code)) + } + return .object(["graphs": .array(graphs)]) + } + + /// Gives a record and its ECG symptoms the events the converter facade is handed for every vector that converts: + /// the record the corpus's sequence, each symptom the next one in the record's order. + /// + /// The ledger numbers the new events of one call in the sorted order of their keys, which are digests, so an + /// export that reserves an ECG and its symptoms together numbers them in no fixed order. Reserving each request + /// on its own first, in the facade's order, numbers them as the facade does; the export then finds every + /// reservation under its own request and reuses it. + private static func reserveFacadeEvents(of record: HealthKitFHIRExporter.Record, through exporter: HealthKitFHIRExporter) throws { + let requests = HealthKitFHIRExporter.Plan(.record(record), exporter: exporter).requests + guard requests.count > 1 else { + return + } + for request in requests { + _ = try exporter.producer.reserve([request], at: GoldenFixtures.conversionInstant) + } + } + + /// An exporter whose options state what `ContentCorpusRecorder.context(for:)` states for `source`. + private static func exporter(for source: ContentCorpusSource) throws -> HealthKitFHIRExporter { + let producer = try ExchangeProducer( + identityScope: base.identityScope, + subject: base.subject, + application: base.application, + host: base.host, + studies: source.context == .linked ? [.test("study-a")] : [], + sequencer: CorpusLedger.sequencer(producerInstance: base.event.producerInstance, nextSequence: ContentCorpusRecorder.sequence) + ) + var options = HealthKitFHIRExporter.Options() + if source.context == .linked { + options.role = .gateway + } + if case .workoutRoute(_, disclosed: true) = source.record { + options.route = .authorized + } + return try HealthKitFHIRExporter(producer: producer, repositoryScope: base.repositoryScope, options: options) + } + + /// The record the exporter takes for `source`, or nil for an ECG whose symptom contexts the vector miscounts. + private static func exporterRecord(_ source: ContentCorpusSource) throws -> HealthKitFHIRExporter.Record? { + switch source.record { + case .electrocardiogram(let reading): + guard reading.symptomContexts == nil else { + return nil + } + let record = try ContentCorpusSamples.electrocardiogram(source, reading: reading) + return .electrocardiogram(record.electrocardiogram, voltages: record.voltageMeasurements, symptoms: record.correlatedSymptoms) + case .heartbeatSeries(let beats): + let record = try ContentCorpusSamples.heartbeatSeries(source, beats: beats) + return .heartbeatSeries(record.series, beats: record.heartbeats) + case .workoutRoute(let locations, _): + let record = try ContentCorpusSamples.workoutRoute(source, locations: locations) + return .workoutRoute(record.route, locations: record.locations) + default: + return .sample(try ContentCorpusSamples.sample(source)) + } + } + + /// A line's output with each rendered warning cut to its registry code, as the exporter reports it. + private static func warningCodes(in output: LosslessJSONValue) -> LosslessJSONValue { + guard case .object(var members) = output, let graphs = output["graphs"]?.elements else { + return output + } + members["graphs"] = .array(graphs.map { graph in + guard case .object(var graphMembers) = graph else { + return graph + } + graphMembers["warnings"] = .array((graph["warnings"]?.elements ?? []).map { warning in + .string(String((warning.text ?? "").prefix { $0 != "(" && $0 != "@" })) + }) + return .object(graphMembers) + }) + return .object(members) + } + + /// Exports one shard's convert vectors and compares each with its line. + @Test(.enabled(if: !ContentCorpusStore.isGenerating), arguments: 0.. 0, "shard \(shard) of the corpus has no convert vector") + #expect(drifted.isEmpty, "\(drifted.count) vectors export otherwise than the corpus pins: \(drifted.prefix(25))") + } +} + +#endif diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Catalog.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Catalog.swift index 10277470e..94c5f73fa 100644 --- a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Catalog.swift +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Catalog.swift @@ -26,10 +26,19 @@ extension ContentCorpusGrid { "uS", "ug", "{drinks}", "{falls}", "{flights}", "{puff}", "{pushes}", "{score}", "{steps}", "{strokes}", "{uvindex}" ] - /// The deletion of a record of every inventory row. + /// The rows whose deletion is also named with the store's UUID disclosed: one per kind of target set (a single + /// Observation, a panel, a session, an ECG with its derived child, a recording document, a clinical record). + static let disclosedRetractions = [ + HKQuantityTypeIdentifier.heartRate.rawValue, HKCorrelationTypeIdentifier.bloodPressure.rawValue, HKWorkoutTypeIdentifier, + HKObjectType.electrocardiogramType().identifier, HKDataTypeIdentifierHeartbeatSeries, "HKClinicalTypeIdentifierLabResultRecord" + ] + + /// The deletion of a record of every inventory row, then of a few rows with the native identifier disclosed. static var retractions: [ContentCorpusVector] { HealthKitContract.rows.map { row in ContentCorpusVector(id: "retraction/\(row.sourceTypeIdentifier)", input: .retract(type: row.sourceTypeIdentifier)) + } + disclosedRetractions.map { type in + ContentCorpusVector(id: "retraction/native-identifier/\(type)", input: .retract(type: type, disclosure: .nativeIdentifier)) } } @@ -58,10 +67,10 @@ extension ContentCorpusGrid { } observations.append((bodyMassIndexID, observation(code: ("http://loinc.org", "39156-5"), quantity: quantity("kg/m2", unit: "kg/m2", value: 1)))) let projected = observations.map { id, resource in - ContentCorpusVector(id: "reverse/\(id)", input: .catalog(projection: .reverse(observation: json(resource)))) + ContentCorpusVector(id: "reverse/\(id)", input: .reverse(observation: json(resource))) } return projected + reverseEdges.map { label, resource in - ContentCorpusVector(id: "reverse/edge/\(label)", input: .catalog(projection: .reverse(observation: json(resource)))) + ContentCorpusVector(id: "reverse/edge/\(label)", input: .reverse(observation: json(resource))) } } @@ -165,12 +174,12 @@ extension ContentCorpusGrid { return resource } - /// The resource as compact JSON with sorted members. - static func json(_ resource: [String: Any]) -> String { - guard let data = try? JSONSerialization.data(withJSONObject: resource, options: [.sortedKeys, .withoutEscapingSlashes]) else { + /// The resource as the nested JSON an input states. + static func json(_ resource: [String: Any]) -> ContentCorpusJSON { + guard let json = try? ContentCorpusJSON(serializing: resource) else { preconditionFailure("every corpus Observation is valid JSON") } - return String(decoding: data, as: UTF8.self) + return json } } diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Metadata.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Metadata.swift index b1c3c7cd8..48d565857 100644 --- a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Metadata.swift +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Metadata.swift @@ -15,6 +15,7 @@ import HealthKit /// Each metadata key valid, wrongly typed and absent, keys a path does not read, and multi-fault precedence. extension ContentCorpusGrid { + /// A 72 bpm heart rate, the record every metadata family varies unless it needs another. static let heartRateRecord = ContentCorpusRecord.quantity(type: heartRate, value: 72, unit: "count/min") /// Every metadata family, in corpus order. @@ -194,11 +195,25 @@ extension ContentCorpusGrid { ] var deviceOmission = ContentCorpusSource(nanHeartRate) deviceOmission.device = .watchWithoutUnitToken - return (cases + [("value-before-device-omission", deviceOmission)]).map { label, source in + return (cases + [("value-before-device-omission", deviceOmission)] + distinctlyRenderedPrecedence).map { label, source in convert("precedence/\(label)", source) } } + /// Fault pairs whose faults render differently, so the output names the one checked first: a year-10000 + /// instant (no FHIR date-time) before a category value and before a metadata component, and an unknown zone + /// before the year-10000 instant of an assessment, which has no value a fault could sit in. + static var distinctlyRenderedPrecedence: [(String, ContentCorpusSource)] { + let yearTenThousand = 253_402_300_800.0 + let activity = ContentCorpusRecord.category(type: HKCategoryTypeIdentifier.sexualActivity.rawValue, value: 1) + let assessment = ContentCorpusRecord.assessment(type: HKScoredAssessmentTypeIdentifier.GAD7.rawValue, score: 6) + return [ + ("effective-year-10000-before-category-value", ContentCorpusSource(activity, start: yearTenThousand, metadata: [:])), + ("effective-year-10000-before-motion-context", ContentCorpusSource(heartRateRecord, start: yearTenThousand, metadata: [HKMetadataKeyHeartRateMotionContext: .integer(3)])), + ("zone-before-assessment-effective", ContentCorpusSource(assessment, start: yearTenThousand, metadata: [HKMetadataKeyTimeZone: .string("Not/A-Time-Zone")])) + ] + } + /// How long a record of the row lasts; a record of another kind is an instant. static func span(_ record: ContentCorpusRecord) -> Double { let type: String? = switch record { diff --git a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Recordings.swift b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Recordings.swift index 948989f33..ede77f110 100644 --- a/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Recordings.swift +++ b/Tests/GroveHealthKitFHIRTests/ContentCorpus/ContentCorpusGrid+Recordings.swift @@ -13,7 +13,7 @@ import GroveFHIRContract import HealthKit -/// ECG evidence edges and every recording and clinical document builder. +/// ECG evidence, precedence and time edges, heartbeat series and workout routes. extension ContentCorpusGrid { /// The conformance fixtures' sinus-rhythm reading: four voltages 2 ms apart at 500 Hz, 72 bpm, no symptoms. static let electrocardiogramReading = ContentCorpusElectrocardiogram( @@ -74,6 +74,76 @@ extension ContentCorpusGrid { + waveformEdges + symptomRelationships return readings.map { label, reading in electrocardiogram(label, reading) } + electrocardiogramFacts + + electrocardiogramPrecedence + electrocardiogramTimes + } + + /// Two faults at once for every pair of adjacent checks of an ECG conversion (zone, lead presence, count, + /// offsets, period, sampling frequency, finite voltages, symptom contexts, symptom validation and status, + /// source period, classification, algorithm version, average heart rate): which one is reported pins their order. + static var electrocardiogramPrecedence: [ContentCorpusVector] { + let present = HKElectrocardiogram.SymptomsStatus.present.rawValue + let chest = ContentCorpusElectrocardiogram.Symptom(type: HKCategoryTypeIdentifier.chestTightnessOrPain.rawValue, value: 2, ordinal: 0xE1) + let headache = ContentCorpusElectrocardiogram.Symptom(type: HKCategoryTypeIdentifier.headache.rawValue, value: 2, ordinal: 0xE1) + let versionThree = zone.merging([HKMetadataKeyAppleECGAlgorithmVersion: .integer(3)]) { $1 } + func source( + _ reading: ContentCorpusElectrocardiogram, + metadata: [String: ContentCorpusMetadataValue] = electrocardiogramMetadata, + reversed: Bool = false + ) -> ContentCorpusSource { + var source = electrocardiogramSource(reading) + source.metadata = metadata + source.end = reversed ? start - 30 : source.end + return source + } + let missingLead = reading { $0.voltages[2].millivolts = nil } + let nanVoltage = reading { $0.voltages[1].millivolts = .nan } + let nonUniform = reading { $0.voltages[2].offset = 0.255 } + let pairs: [(String, ContentCorpusSource)] = [ + ("zone-before-missing-lead", source(missingLead, metadata: electrocardiogramMetadata.merging([HKMetadataKeyTimeZone: .string("Not/A-Time-Zone")]) { $1 })), + ("missing-lead-before-count", source(reading(missingLead) { $0.reportedCount = 3 })), + ("count-before-offsets", source(reading(reading { $0.reportedCount = 3 }) { $0.voltages[0].offset = -0.002 })), + ("offsets-before-period", source(reading(nonUniform) { $0.voltages[3].offset = -1 })), + ("period-before-frequency", source(reading(nonUniform) { $0.samplingFrequency = 250 })), + ("frequency-before-voltages", source(reading(nanVoltage) { $0.samplingFrequency = 250 })), + ("voltages-before-symptom-contexts", source(reading(symptoms(present, [chest])) { reading in + reading.voltages[1].millivolts = .nan + reading.symptomContexts = 0 + })), + ("symptom-contexts-before-symptom-validation", source(reading(symptoms(present, [headache])) { $0.symptomContexts = 0 })), + ("symptom-validation-before-source-period", source(symptoms(present, [headache]), reversed: true)), + ("symptoms-status-before-source-period", source(reading { $0.symptomsStatus = 99 }, reversed: true)), + ("symptoms-status-before-classification", source(reading(reading { $0.symptomsStatus = 99 }) { $0.classification = 99 })), + ("classification-before-algorithm-version", source(reading { $0.classification = 99 }, metadata: versionThree)), + ("algorithm-version-before-average-heart-rate", source(reading { $0.averageHeartRate = .nan }, metadata: versionThree)) + ] + return pairs.map { label, source in + convert("electrocardiogram/precedence/\(label)", source) + } + } + + /// The base ECG at instants its exact timing has to carry: a start a quarter second before a minute, so the + /// first voltage falls into the next one; a local year past 9999; 1500 in Los Angeles (local mean time) and in + /// UTC; and both occurrences of Los Angeles's repeated 2026 hour. + static var electrocardiogramTimes: [ContentCorpusVector] { + func at(_ instant: Double, metadata: [String: ContentCorpusMetadataValue] = electrocardiogramMetadata) -> ContentCorpusSource { + var source = electrocardiogramSource(electrocardiogramReading) + source.start = instant + source.end = instant + 30 + source.metadata = metadata + return source + } + let utc: [String: ContentCorpusMetadataValue] = [HKMetadataKeyTimeZone: .string("UTC"), HKMetadataKeyAppleECGAlgorithmVersion: .integer(2)] + let instants: [(String, ContentCorpusSource)] = [ + ("start-carries-into-minute", at(1_787_005_859.75)), + ("year-10000", at(253_402_329_600)), + ("pre-reform-1500", at(-14_831_769_600)), + ("pre-reform-1500/utc", at(-14_831_769_600, metadata: utc)), + ("repeated-hour-first", at(1_793_521_800)), + ("repeated-hour-second", at(1_793_525_400)) + ] + return instants.map { label, source in + convert("electrocardiogram/time/\(label)", source) + } } /// Correlated symptoms: one, several sorted by type and UUID, refused types and duplicates, a status that @@ -226,10 +296,12 @@ extension ContentCorpusGrid { } } + /// A 30-second ECG at the base instant stating `reading`, with the zone and algorithm version a watch states. static func electrocardiogramSource(_ reading: ContentCorpusElectrocardiogram) -> ContentCorpusSource { ContentCorpusSource(.electrocardiogram(reading: reading), end: start + 30, metadata: electrocardiogramMetadata) } + /// The vector converting the base ECG with `reading`, under `electrocardiogram/