Repository navigation
Conversation
056eab5 to
54c9d85
Compare
|
Rebased onto the current Checked after the rebase:
LoopTests weren't run for this update. On this build machine the test host hangs before XCTest connects, with both ad-hoc and automatic simulator signing, so that's still to do. This replaces #2615, which targeted 🤖 Generated with Claude Code |
|
Reviewed the full 79-file diff at Critical (confidence 90–100)
Important (confidence 80–89)
Verification
The PR description now records the fixes, current validation and limitations, and corrects the stale statement that #2615 is still open. No further findings met the skill's confidence threshold in this pass. |
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QHnVP5sTMyrVG4zz5Wp4KM
…dling Build Now, Trends and Logbook around Loop's existing controllers and stores. Keep delivered quantities and history partitions accurate, preserve editing drafts across updates, propagate load failures and share chart averages. Per-day Trends figures leave out the day in progress and share insulin's days, the day chart names a day without readings, and the Logbook carb editor receives Loop updates on the main thread. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Driving the error states in the simulator (pump fault, comms issue,
suspension, sensor warmup, signal loss, sensor failed) showed that a
device problem could be off-screen: the status pills scrolled sideways,
so during warmup the CGM pill was past the edge and nothing visible said
so.
- Status pills wrap instead of scrolling.
- A device highlight, or a loop that hasn't completed for 15 minutes,
gets a notice under the pills with the device's message and icon, what
it means for Loop, and a tap through to the device; most serious first.
- Two-line plugin highlights ("Signal\nLoss") are joined.
- When Loop pauses closed loop (no CGM session or data), the pill says
"Closed loop paused" instead of "Open loop".
- Loop's status rows (No Recent Glucose, Tap to Resume, bolus progress,
presets) take the card shape in the new interface; the non-critical
pump notice is left out while the Resume row shows.
LoopTests: 323 pass on the iPhone 17 Pro simulator (iOS 26.3).
On next-dev, Loop's status rows are already drawn as rounded cards (LOOP-5437), so the
new interface keeps them as they are rather than adding a second card behind them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QHnVPACb9uRhdQPgF5h2mj
Settings gets an "Appearance and App Icon" screen: - Appearance: System, Day or Night. It sets the window's interface style, so it applies to the whole app (new and classic interface, sheets included) and takes effect without a relaunch. - App Icon: Classic (the primary icon, unchanged), Day, Night, and Day and Night, whose dark appearance variant follows the home screen's light or dark icons. Day, Night and Day and Night are alternate icon sets in DerivedAssetsBase, listed in the Loop target's ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES; small preview image sets show them in the picker because iOS doesn't expose alternate icons as images. The new icons keep Loop's ring and add the blue reading dot from the Now screen, on a light ground for Day and a midnight-blue one for Night. The artwork was generated with GPT image generation and chosen from two takes each. iOS can report an error from its "icon changed" alert even though the icon changed (the iOS 26.3 simulator does this every time), so the picker trusts the icon iOS reports afterwards. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QHnVPAQn8LyVAJrZEA3f2T
Every string the new interface shows or speaks now goes through
NSLocalizedString with a translator comment, and Localizable.xcstrings
gains 213 keys with translations in all 23 of Loop's other languages
(ar cs da de es fi fr he hu it ja nb nl pl pt-BR ro ru sk sv tr uk vi
zh-Hans). Fourteen existing keys the redesign reuses ("Bolus", "%1$@ U",
"Settings", ...) keep their translations and gain the languages they
were missing.
- Sentences with values are whole keys with positional placeholders,
and counts ("%lld days", "%lld shorter gaps", "Loop · %lld changes")
use plural variations, so no text is glued together in code.
- Numbers, dates, ranges and durations follow the user's locale:
LoopFormat.number replaces String(format:), date ranges use
DateIntervalFormatter and durations DateComponentsFormatter.
- The Trends one-day period has its own key, "Day (Trends period)",
because "Day" is also the light appearance and icon name and some
languages need different words for the two.
- The Now action buttons wrap to two lines and tile labels scale down,
so longer languages don't truncate.
- The CSV export stays English with '.' decimals on purpose; it is
data for spreadsheets, not display text.
Translations follow Loop's existing terms per language and were checked
for placeholder and plural-category integrity. Each language was run
through the simulator with NSShowNonLocalizedStrings. They have not
been reviewed by native speakers.
On next-dev the catalogue merge keeps next-dev's own entries and comments and adds the
redesign's keys and translations. The pre-meal menu strings are left out because next-dev
opens pre-meal from the Presets screen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QHnVPACb9uRhdQPgF5h2mj
…esign The home screen widget and the Live Activity now follow the redesign's rules from the Now screen: a white SF Pro Rounded glucose number with a blue trend arrow, low and high said in words rather than by tinting the number, Loop's state as a dot with words, sunken tiles, and device problems written out. - Widget: the Now hero with COB and Forecast tiles; the medium size adds Add carbs, Bolus, Pre-meal and Presets in the Now screen's styles. - Lock Screen: hero, the Now chart's style (blue readings, dashed prediction, target band) and the configured bottom row as one-line tiles, within the 160 pt limit. - Dynamic Island: white number and blue arrow, the change or "Low"/"High" in words with a loop dot, a keyline tinted for low and high, and an expanded view with a full-width status line and the chart. They follow the New Interface setting: the app mirrors it into the app group, reloads widget timelines and redraws the Live Activity when it changes, so classic users keep the classic widget and Live Activity. LoopDesign.swift and the redesign's colour sets are shared with the widget target. The widget entry gains the CGM highlight and COB from the existing extension context. The widget catalogue gains the redesign's strings in all 24 languages, reusing Loop's translations, plus a short "Forecast" tile label. The Arabic "in 5 min" now uses an Arabic-Indic digit in both catalogues. On next-dev the widget buttons use next-dev's shared Deeplink type, which replaced SystemActionLink, and glucose units are LoopUnit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QHnVPACb9uRhdQPgF5h2mj
Parity with next-dev: - The IOB tile opens next-dev's Insulin Delivery Log (dose details, manual dose entry), shared with the classic IOB chart through showInsulinDelivery. - The Loop pill opens next-dev's LoopStatusModalView. Device and loop errors still open the last error first. The new interface has no HUD to keep the modal's "ago" current, so it is set before presenting; without it the modal reported "Automation was unsuccessful" while Loop was running. - Settings hides next-dev's Statistics row in the new interface, which the Trends tab covers. Current Setup stays. - The Day page hides the tab bar when pushed from Now, like the Insulin, Carbohydrates and Predicted Glucose screens. Accuracy: - Basal totals follow next-dev's InsulinDeliveryHistory: from the first dose record, time without a basal record counts at the pump's programmed rate instead of as no insulin. Trends now agrees with next-dev's Statistics on basal (25.6 vs 25.3 U/day on the same data). Remaining differences are the period: Trends' 7 d includes today and averages complete days. - Pump alarms in the Logbook show the pump's own alarm text, or "Pump alarm", rather than the event's debug title. Performance: - Loop runs decode only date, reason and errors for the local window via DosingDecisionStore.getDosingDecisions, instead of paging every stored decision: Trends loads in 0.5-1.8 s instead of 6.6-16.4 s. - basalSegments finds the covering record by binary search bounded by the running furthest end, instead of a linear scan per cut: a week of five-minute records builds in 0.4 s instead of 10.8 s. - The start of the local insulin records is cached for five minutes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QHnVP5sTMyrVG4zz5Wp4KM
- Trends has a "Basal and bolus" card above Insulin per day. It shows a ratio bar, basal and bolus in units and percent, the manual and automatic bolus, and the total. For a period it's the average per day, over the same days as the Insulin per day figure; for today it's "so far". - The day page shows the same card in place of the bolus and basal tiles. - Each Logbook day header has a hairline ratio bar and "Basal x · Bolus y · z U" under the date. - Bolus gets its own colour, a deeper orange than basal's pale fill, so the two read apart by lightness as in Glooko and Tidepool, with no new hue. Automatic bolus is the same colour hatched (tinted in hairline bars), on the timeline, the daily bars and the legends. - A dose in Apple Health that doesn't say whether it was automatic is no longer counted as manual. While any bolus in range is unclassified, the manual and automatic detail is hidden rather than guessed. - The CSV export adds manual_bolus_u and auto_bolus_u columns, which are blank for days with an unclassified bolus. - The new strings are translated into the redesign's 23 languages. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QHnVP5sTMyrVG4zz5Wp4KM
Pushed inside the Logbook tab, the carb editor and its bolus screen kept the floating tab bar over their bottom button (Save Carbs & Deliver / Save without Bolusing). The editor now opens as a sheet with Cancel, the way Add carbs does on Now. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QHnVP5sTMyrVG4zz5Wp4KM
415926d to
1b6efc9
Compare
|
Rebased onto the current Conflicts
Fix found in testing (
Checked on the
LoopTests were not run on this simulator. The hosted test runner hangs before connecting ("The test runner hung before establishing connection"). It hangs the same way on plain 🤖 Generated with Claude Code |
Basal's edge was the same orange as bolus (1.04:1 in dark mode), and the pale basal fill barely showed against the card, so the two read as one. Basal is now paler with a quiet tan edge, bolus is deeper in light mode, and the edge and bolus are at least 3:1 apart in both modes. Bolus marks also get a thin card-coloured gap wherever they touch basal or each other: in the daily bars, the split bar and the day timeline. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QHnVP8UwbiZYLRjsYUYXhE
…kinds apart in the Logbook Add carbs - New CarbEntryScreen on top of the unchanged CarbEntryViewModel: a large amount, "How fast it absorbs" cards that draw Loop's own absorption curve (Fast, Medium, Slow, Other), "Eaten" quick times plus a time picker, and a pinned Continue that hands over to the existing bolus screen. - Other shows "Custom" and no curve until it is chosen. - Any scroll or the Done button puts the keyboard away, so the form stays reachable at accessibility text sizes; the cards and times go 2 x 2 there. - Used from the Now screen and for editing carbs in the Logbook when the redesign is on; the classic interface keeps CarbEntryView. Trends, one day - Shows the same timeline card as Now's "Today so far" (shared as DayTimelineCard) instead of the AGP and the single Insulin per day bar. - Tiles read Insulin, Carbs and Boluses with whole counts, and "3 entries" is a proper plural. - Carb markers closer than the label spacing share one label with their total, placed after the last marker, so labels no longer overprint. Logbook - Manual bolus, automatic bolus and basal use the charts' encoding: solid, hatched and pale basal tiles; the day key and hairline bar match. - Two or more automatic boluses in a row fold into one "Automatic boluses" row that opens the list. - At accessibility sizes the amount sits under the title and the day totals move under the date. Strings added in all 23 languages (unreviewed translations). Tests: DayHistory.clipped(to:) and the automatic-bolus folding. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QHnVP8UWK6Li65s9wma3FF
…s for PR LoopKit#2621 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QHnVP8UWK6Li65s9wma3FF
|
Reviewed the complete PR #2621 diff (85 changed files) against Critical
Important
The favourite editor also receives the effective food emoji. The exact date/time controls stack at accessibility sizes; the final AX XXXL capture confirms the label stays readable. Final diff review found no further issues at the skill's ≥80 confidence threshold. Verification
The PR description contains five simulator screenshots and the same coverage limits. The review build uses the PR sources and clean LoopKit dependencies, without the unrelated local Glooko host edits. |
This is the redesigned interface from #2615 (Now, Trends, Logbook and Settings tabs), rebuilt on
next-dev. #2615 is now closed; its description covers the design, the error states, the appearance and icon options, the localisation and the widget, and all of that applies here. This description covers what changed to fitnext-dev.The first six commits follow #2615's commits one for one. The later commits are the review, parity and fix updates listed below. The branch is rebased on
next-deve0eb9856(30 October 2026).What changed for next-dev
next-devhostsStatusTableViewControllerinside the SwiftUIStatusTableViewwith its own action bar. In the new interface the tabs wrap that hosting controller and the action bar is hidden (StatusTableView.showsActionTabs(_:)), because Now has its own Add carbs, Bolus and Presets buttons. The classic interface isnext-dev's screen, unchanged.LoopDataManager.algorithmDisplayState,activeInsulinandactiveCarbs, plusSettingsManagerandTemporaryPresetsManager, instead ofgetLoopStateandLoopSettings. The day pages' insulin and carbs on board come from two smallLoopDataManagerhelpers. They usenext-dev's own maths: doses annotated with basal history, and the carb absorption review.next-dev, pre-meal is one of the presets on the Presets screen, so the Now screen has one Presets button that opens it, rather than Add a redesigned interface with Now, Trends and Logbook tabs #2615's pre-meal menu. The button shows the active preset's name.next-dev's active-preset banner stays above the screen.DeviceDataManager.closedLoopDisallowedLocalizedDescription(no sensor session, or a manual temp basal).next-devalready draws No Recent Glucose, Tap to Resume and bolus progress as rounded cards, so Add a redesigned interface with Now, Trends and Logbook tabs #2615's card styling for them is left out.DeeplinkManageris gone onnext-dev.LoopAppManager.handle(_:)switches to the Now tab before opening the carb, bolus or presets screen. The widget's buttons use the sharedDeeplinktype.StatusTableViewController, which is only in the window while Now is selected. Without this, choosing a service in Add Service from Trends or Logbook showed nothing.SettingsManager.dosingEnabled.LoopDataManager.automationHistorykeeps only 36 hours, too short for the 90-day view.next-dev's entries and comments and adds the redesign's keys and translations.next-dev's Statistics screen gains translations for the labels it shares with Trends: Average, GMI, High and Low.next-devhas its ownAGPChartView(Statistics), so the Trends chart isTrendsAGPChart.Screenshots (iOS 26.3 simulator, Pump and CGM Simulators)
Testing
On the iOS 26.3 simulator, with the Pump and CGM Simulators and data carried over from a
devinstall:LoopTests: 389 of 391 pass. The two failures,
BolusEntryViewModelTests.testCarbEntryDateAndAbsorptionTimeStringand…String2, fail the same way on plainnext-devon the same simulator ("12:00 PM" against "12:00").Known limitations
devstored before the upgrade didn't come back fromDosingDecisionStore.executeDosingDecisionQuery, which drops records it can't decode. So "Loop active" on Trends starts at the upgrade. I haven't confirmed which field fails to decode.LoopAlgorithmnordev'sLoopMathsets a floor.🤖 Generated with Claude Code
https://claude.ai/code/session_01QHnVPACb9uRhdQPgF5h2mj
Review update — 28 October 2026
A comprehensive
code-reviewer-cxreview of the full PR found four issues, fixed in42b476ad:Both added regression tests failed on the original code and pass after the fixes. The two affected suites pass all 33 tests. Simulator app and test builds succeed.
With an isolated XCTest runner using the compiled production and test objects, 409 of 411 executed tests pass. The other two are the existing
BolusEntryViewModelTests.testCarbEntryDateAndAbsorptionTimeString/…String2locale-format failures, reproduced on the original PR head. FourDeviceDataManagerTestsremain unverified because the isolated runner lacks HealthKit's registered app-host context. The normal Xcode-hosted run remains blocked during test-host launch; this is not a passing full hosted-suite result.The
loopsimulator was driven through preset activation, carb entry and saving, Logbook editing, CSV sharing, day navigation and Settings presentation. After the fixes, Now, the day pages, Logbook, Settings and the 90-day Trends view were checked again. Widget and Live Activity changes were reviewed and built; their runtime rendering remains unverified in this review.Parity update — 28 October 2026
Checked the new interface screen by screen against
next-dev's own screens and totals, on theloopsimulator (Xcode 27.1, iOS 27.0, Pump and CGM Simulators, 90 days of generated history). Fixed in41e9535a:Parity
next-dev's Insulin Delivery Log, which has dose details and manual dose entry. The classic IOB chart uses the sameshowInsulinDelivery, so the two can't drift apart.next-dev'sLoopStatusModalView. A newer device or loop error still opens the error first. With no classic HUD to keep the modal's "ago" current, it showed "Automation was unsuccessful" while Loop was running; the value is now set before the modal is presented.next-dev's Statistics row in the new interface, because Trends covers glucose metrics, time in range, AGP and daily insulin. Current Setup stays, as it has no counterpart.next-dev's Insulin, Carbohydrates and Predicted Glucose screens do.Accuracy
next-dev'sInsulinDeliveryHistoryrule. From the first dose record, time without a basal record counts at the pump's programmed rate, rather than as no insulin. On the same data, Trends andnext-dev's Statistics now agree on basal (25.6 and 25.3 U/day). The remaining gap in total insulin comes from the period, not the maths:Performance (debug build, simulator)
loopRuns(), which paged and fully decoded every stored dosing decision. It now decodes only date, reason and errors for the local window throughDosingDecisionStore.getDosingDecisions, and loads in 0.5–1.8 s.basalSegmentsscanned every record for every cut. A binary search bounded by the running furthest end brings it to 1.7 s. The 90-day view spends about 9 s reading Apple Health for the 83 older days.Noticed, outside the redesign (not changed here)
next-dev's simulated history writes pump events without reconciling them, sogetNormalizedDoseEntriesignores them, and Trends, Statistics and the Insulin screen show no generated insulin. The generator also adds a bolus about every 20 minutes, although its comment says eight a day. For these screenshots I adjusted it locally (not committed).next-dev's Carbohydrates screen showed "40 g absorbed" for a 10 g entry.The "Alarms are turned OFF" banner in the screenshots is
next-dev's warning: the simulator can't grant AlarmKit or Critical Alerts.Screenshots (iOS 27.0 simulator)
Tests:
LoopHistoryMathTestsgains a regression for the programmed-rate rule. As noted above, the Xcode-hosted LoopTests run still hangs at test-host launch on this machine, so the new test has been compiled but not run there.Basal and bolus split — 29 October 2026
Trends, the Day page and the Logbook now show basal and bolus explicitly, with the total, instead of one insulin number.
#6C4E87, bolus#BD9CBB) and Tidepool (blue: basal#19A0D7, bolus#7CD0F0, automated#00B2C3). Both keep insulin in one colour family, tell basal from bolus by lightness, and reserve red for warnings. Loop does the same in its own orange: blue is Loop's glucose colour, and the IOB, classic screens, watch and widgets all stay orange.MetadataKeyAutomaticallyIssuedis no longer counted as manual. While any bolus in range is unclassified, the manual and automatic detail is hidden rather than guessed.manual_bolus_uandauto_bolus_ucolumns, which are blank for a day with an unclassified bolus.Tests
testInsulinSplitSeparatesManualAutomaticAndUnclassifiedBolus. Changed: the CSV test now checks the ten columns, including a day with an unclassified bolus.xctestagent on the built test bundle.LoopHistoryMathTests: 22 tests, 0 failures.DeviceDataManagerTests, which needs a HealthKit host: 413 tests, with only the 2 knownBolusEntryViewModelTests12-hour-clock failures. These also fail without this change.Checked on the simulator: Trends for one day (today), 14 days and 90 days, the weekly bars, the Logbook, and the Day page, in light and dark and at Accessibility Extra Large text. The card, the Summary tile and the Logbook totals agree.
Basal and bolus contrast — 30 October 2026
In use, basal and bolus were still too alike. The part of basal you notice is its edge line, and it was nearly the same orange as bolus: 1.04:1 in dark mode and 1.43:1 in light. The pale basal fill barely shows against the card (1.34:1).
#FCE3C2light,#43301Bdark.#E3B983light,#6E5232dark.#A9480A, ink#8A3A06). Dark mode bolus is unchanged.Add carbs, Trends Day and Logbook insulin kinds — 31 October 2026
Add carbs is redesigned.
CarbEntryScreendrives the existingCarbEntryViewModelunchanged, so validation, warnings, favourite foods and the hand-off to the bolus screen all behave as before.CarbMath) on a shared time axis, so a slow meal draws as a long, low ramp. Other shows "Custom" until it is chosen, then offers a food type and an absorption time.CarbEntryView.Trends → Day now shows the same timeline card as Now's "Today so far", instead of an AGP with one day of data. The tiles use whole counts and say "Insulin", "Carbs" and "Boluses". Carb entries close together share one label showing their total, so labels no longer print over each other.
Logbook:
Strings: new strings are added in all 23 languages. These translations are mine and haven't been reviewed by native speakers.
Testing:
LoopTests: 429 tests, 2 failures. Both are the existingBolusEntryViewModelTests.testCarbEntryDateAndAbsorptionTimeString{,2}assertions that expect a 12-hour clock (they fail the same way without this PR).DayHistory.clipped(to:)and the folding of automatic boluses.3fa82de3on a physical iPhone 18 Pro (iOS 27.2) running Omnipod 5 and Dexcom G7 in closed loop. Loop relaunched in closed loop, and Now, Trends and the Logbook load with real pump history. Nothing was delivered or changed during this check.A simulator issue found along the way, not caused by this PR: the Pump Simulator can lose a bolus if Loop is killed before the bolus is finalised.
MockKit/UnfinalizedDose.rawValuestoresdecisionIdas aUUID, which isn't a property-list type, so savingPumpManagerStatefails ("Error saving PumpManagerState") whenever a dose with a decision ID is in progress. After a restart, the pump state has no bolus, and the next sync'sreplacePendingEventspurges the mutable event. StoringdecisionId.uuidStringwould fix it. This only affects the simulator pump.Comprehensive review — 31 October 2026
Reviewed the complete PR against
next-deve0eb9856usingcode-reviewer-cx. Fixes are in088e6bbd.Simulator verification: Xcode 27.1, iOS 27.0, Device Hub
loop, Pump and CGM Simulators. Built from an isolated PR checkout and clean LoopKit checkout, excluding the unrelated local Glooko integration changes.Exercised favourite selection and speed changes, Meal Bolus hand-off, saving and editing carbs through Logbook, every Logbook filter, folded automatic-dose details, day navigation, all Trends periods through 90 days, previous/next periods, CSV/PDF sharing, classic/redesigned interface switching, dark mode, AX XXXL and the maximum-meal warning. Checked the final accessibility layout after rebuilding. The medium Home Screen widget now has runtime verification, including glucose, COB, forecast and its four actions. Lock Screen and expanded Live Activity layouts were not re-exercised in this review.
Tests: the two bug regressions fail with the pre-fix scheduling and target-selection behaviour restored; all three new tests pass with the fixes. The isolated XCTest run executes 432 tests: 430 pass, two fail. Both failures are the existing
BolusEntryViewModelTests.testCarbEntryDateAndAbsorptionTimeString{,2}12/24-hour formatting assertions, also reproduced with the pre-fix behaviour.Coverage limit: the normal Xcode-hosted run stalled at launch and was stopped after 150 seconds without a completed test result. Four
DeviceDataManagerTestsremain unverified: HealthKit reports a nil client bundle identifier, including in a separately registered disposable test app. This is not a clean full hosted-suite pass.