Skip to content

Choose the sync identifier for each new carb entry - #2587

Merged
ps2 merged 3 commits into
next-devfrom
carbstore-sync-identifier
Oct 19, 2026
Merged

ps2 merged 3 commits into
next-devfrom
carbstore-sync-identifier

Conversation

@ps2

@ps2 ps2 commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Requires LoopKit/LoopKit#654, where a NewCarbEntry carries its own sync identifier, so that a retried save is stored once, and edits use CarbEntryUpdate.

Each place that creates a new entry now chooses its identity:

Path Identifier
Carb entry screen → bolus screen one per carb entry screen, so saving again after a failed bolus does not add the carbs twice
Watch carb and bolus flow one per carb entry under consideration, sent inside the entry; a retry after a lost reply resends the same entry
Watch messages whose carb entry has no identifier (older watch apps) refused: nothing is stored or delivered, and the watch shows its bolus failure
Simple bolus calculator fresh per save, as before
Remote carb commands fresh per command, as before
Missed-meal prefill, simulated data fresh

Edits

The bolus screens took a nullable new entry plus a nullable original entry. They now take a CarbEntryChange, which is either .add(NewCarbEntry) or .edit(StoredCarbEntry, CarbEntryUpdate), and saving calls addCarbEntry or replaceCarbEntry to match. recommendManualBolus and generatePrediction take the same value.

Older watch apps

SetBolusUserInfo and GetBolusRecommendationUserInfo now refuse a message whose carb entry doesn't decode. Without that, an older watch app's entry would decode as no carbs, and its bolus would go ahead without them.

Not covered

Remote commands carry their own identity, but ServicesManager.deliverRemoteCarbs doesn't receive it yet; passing it through needs a LoopKit delegate change and is left for a follow-up.

Testing

  • LoopTests: 333 pass on the iOS simulator against CarbStore: carry the sync identifier on new carb entries LoopKit#654. New tests cover saving a new entry from the bolus screen, a watch message without carbs, and a watch carb entry without an identifier being refused. The edit-path tests now check that replaceCarbEntry is called.
  • The watch app compiled in the same build.
  • Not yet exercised on a device.

CarbStore.addCarbEntry now takes the entry's identity from the caller
(LoopKit/LoopKit#654), so each caller decides when a save is a retry of
the same entry.

- Bolus entry screen: one identifier per screen, so saving again after a
  failed bolus does not add the carbs twice.
- Watch carb and bolus flow: one identifier per carb entry under
  consideration, sent in SetBolusUserInfo ("cs"). A retry after a lost
  reply reuses it; the phone stores the carbs once. Messages from watch
  apps without the field get a fresh identifier, as before.
- Simple bolus calculator and remote carb commands: a fresh identifier per
  save, as before. Remote commands carry their own identity, but the
  services delegate does not pass it through yet.
ps2 added 2 commits October 16, 2026 00:14
A watch app that predates the identifier would get a fresh one per
message, so a retry after a lost reply would add the carbs twice. Reject
the whole message instead, before anything is stored or delivered; the
watch shows its existing bolus failure, as for an expired recommendation.
Follows LoopKit/LoopKit#654, where NewCarbEntry now carries its sync
identifier and edits use CarbEntryUpdate.

The bolus screens take a CarbEntryChange, either a new entry or an edit
of a stored one, in place of the nullable new-entry and original-entry
pair, and saving switches on it. The carb entry screen chooses one
identifier per screen, so saving again after a failed bolus stores the
carbs once.

The watch puts the identifier in the entry it sends, replacing the
separate cs key. SetBolusUserInfo and GetBolusRecommendationUserInfo now
refuse a message whose carb entry doesn't decode. Without that, an older
watch app's carbs would decode as no carbs and its bolus would go ahead
without them; now nothing is stored or delivered, and the watch shows its
bolus failure.
@ps2
ps2 marked this pull request as ready for review October 19, 2026 12:49
@ps2
ps2 merged commit b557449 into next-dev Oct 19, 2026
ps2 added a commit to LoopKit/LoopWorkspace that referenced this pull request Oct 19, 2026
Loop: issue reports to the LoopKit developers (LoopKit/Loop#2585), even
alarm loudness (LoopKit/Loop#2589), stop AlarmKit alarms after a relaunch
(LoopKit/Loop#2590), alarms play through silent mode (LoopKit/Loop#2591),
carb entry sync identifier (LoopKit/Loop#2587).

LoopKit: watch glucose duplicate crash (LoopKit/LoopKit#655), chart
back-gesture (LoopKit/LoopKit#656, LoopKit/LoopKit#658), iOS 17.6 and
watchOS 10.6 (LoopKit/LoopKit#659), previous pump's reservoir values
(LoopKit/LoopKit#657), carb entry sync identifier (LoopKit/LoopKit#654).

LibreLoop: not-an-Abbott-product notice (LoopKit/LibreLoop#25), iOS 17.6
(LoopKit/LibreLoop#26), backfilled readings in Recent Readings
(LoopKit/LibreLoop#27).

LibreTransmitter: forward the newest trend reading (LoopKit/LibreTransmitter#58).

EversenseKit and MixpanelService: iOS 17.6 (LoopKit/EversenseKit#7,
LoopKit/MixpanelService#9).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant