EdgeIngest class
Transport-independent, pure-Dart consumer of the Synheart edge wire contract (watch → phone). This is the phone-side counterpart to the watch producer; it exists so every Flutter app stops re-implementing watch→phone ingest — the canonical parse/validate/dedupe/ack logic lives here once.
It is the Dart member of the cross-platform EdgeIngest matrix and mirrors
the Kotlin (ai.synheart.core.edge.EdgeIngest) and Swift
(SynheartCore.EdgeIngest) implementations for behaviour parity: same
callback names, same dedupe-by-artifact_id, same lowercase-hex SHA-256
hash policy, same absent/out-of-set hsi_version flagging, and the same
{ "command": "artifact_ack", "artifact_ids": [...] } ACK body shape.
It holds no Flutter import so it compiles and unit-tests standalone
(dart test / flutter test). Logging goes through dart:developer log
by default, overridable via logSink so a host can route into
SynheartLogger without this core taking a Flutter dependency.
Contract mapping (Synheart edge wire contract)
- §3.1
hr_sample→ EdgeIngestListener.onHrSample / HrEvent - §3.2
bio_sample→ EdgeIngestListener.onBioSample / BioEvent - §3.3
hsi_artifact→ validate hash (§5) + version (§0), dedupe (§5), then EdgeIngestListener.onArtifact / ArtifactEvent - §3.4 / events → EdgeIngestListener.onSessionEvent / SessionEventWrap
- §4/§5 ACK → drainPendingAcks / buildAckBody / drainAckBody
Malformed or unknown bodies are dropped + logged; this class never throws.
Constructors
-
EdgeIngest({EdgeIngestListener? listener, Set<
String> supportedHsiVersions = EdgeIngest.supportedHsiVersions, void logSink(String message)?})
Properties
-
events
→ Stream<
EdgeEvent> -
Broadcast stream of typed edge events (Flutter ergonomics). Fires in
lock-step with the listener callbacks.
no setter
- hashCode → int
-
The hash code for this object.
no setterinherited
- listener → EdgeIngestListener?
-
Optional typed callbacks (parity with the Swift
Delegate/ KotlinListener). All hooks are optional.final -
pendingAckIds
→ List<
String> -
Ids accepted but not yet drained into an ACK (read-only snapshot).
no setter
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
Methods
-
buildAckBody(
List< String> artifactIds) → Map<String, dynamic> ? -
Build the §4/§5 ACK command body for
artifactIds:{ "command": "artifact_ack", "artifact_ids": [...] }. Returns null whenartifactIdsis empty (nothing to ack). -
dispose(
) → Future< void> - Release the broadcast stream controller. Idempotent.
-
drainAckBody(
) → Map< String, dynamic> ? - Drain pending acks and build the ACK body in one step. Null when empty.
-
drainPendingAcks(
) → List< String> - Snapshot the ids accepted since the last drain and clear the pending set, in arrival order. Use with buildAckBody (or drainAckBody) to send the ACK on the command channel; ids are considered handed off once drained.
-
ingest(
Map< String, dynamic> body) → EdgeOutcome -
Consume one decoded wire body. Routes by
type(§1). Never throws: malformed/unknown bodies return Dropped and are logged. -
ingestRaw(
String json) → EdgeOutcome - Convenience: parse a raw JSON string body and dispatch. Never throws.
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
seenCount(
) → int - Number of distinct artifact ids seen (accepted) so far.
-
toString(
) → String -
A string representation of this object.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited
Static Methods
Constants
- commandArtifactAck → const String
- poisonPillThreshold → const int
-
After this many hash mismatches for the SAME
artifact_id, the artifact is dead-lettered (hard error + ack-to-discard) so a deterministically-corrupt artifact stops resending forever (contract §5). - seenLruCapacity → const int
- Cap of the seen-artifact LRU. Re-acking a long-evicted stray is harmless per contract §5, so eviction is safe.
-
supportedHsiVersions
→ const Set<
String> - EDGE-WIRE-CONTRACT.md §0 — supported inner HSI payload versions for consumers in this generation. A payload outside this set (or absent) is flagged/logged as producer drift but still surfaced.
- typeBioSample → const String
- typeHrSample → const String
- typeHsiArtifact → const String