Skip to content

fix(ci): restore Android lint compatibility#2

Merged
hyochan merged 9 commits into
mainfrom
fix/daily-build-green-2026-05-08
May 9, 2026
Merged

fix(ci): restore Android lint compatibility#2
hyochan merged 9 commits into
mainfrom
fix/daily-build-green-2026-05-08

Conversation

@hyochan

@hyochan hyochan commented May 7, 2026

Copy link
Copy Markdown
Member

Summary

  • update AGP from 8.7.3 to 8.13.2
  • update the Gradle wrapper distribution from 8.10.2 to 8.13
  • keep both tools on major version 8 while restoring Kotlin 2.3-compatible Android lint
  • realign the iOS setup UI test with current labels and notification permission behavior
  • add an accessibility label for the icon-only iOS send action
  • avoid Xcode 15-only Swift compile failures in ObservableObject dictionary updates and member label interpolation

Why

The daily root build failed on main in :androidApp:lintAnalyzeDebug because AGP 8.7.3 lint expected older Kotlin metadata and could not analyze Kotlin 2.3.0 outputs. Android's AGP 8.13 release notes document Kotlin 2.3 support in AGP 8.13.2 and Gradle 8.13 as the minimum Gradle version: https://developer.android.com/build/releases/agp-8-13-0-release-notes

The iOS E2E test was stale against the current SwiftUI labels and notification prompt flow. GitHub's iOS CI runner also uses Xcode 15.2, which rejected in-place @published dictionary mutations and direct interpolation of a user-id suffix collection.

Validation

  • ./gradlew build --stacktrace
  • ./gradlew build --offline --quiet
  • ./gradlew :shared:serverTest --offline --quiet
  • ./gradlew :server:test
  • ./gradlew :androidApp:assembleDebug
  • ./gradlew :androidApp:testDebugUnitTest
  • ./gradlew :androidApp:assembleDebug :androidApp:connectedDebugAndroidTest
  • xcodegen generate
  • xcodebuild -project DeeplineIOS.xcodeproj -scheme DeeplineIOS -destination id=9D0E2D78-A57A-4AC8-8486-71D3B40E78CC -configuration Debug test CODE_SIGNING_ALLOWED=NO

Optional quality tasks remain unwired in this repo:

  • ./gradlew detekt -> task not found
  • ./gradlew ktlintCheck -> task not found

Summary by CodeRabbit

  • New Features

    • Improved accessibility labels for chat input controls that adapt based on input state.
  • Bug Fixes

    • Fixed user identifier display formatting in member lists.
  • Chores

    • Updated build tools and dependencies to latest stable versions.

AGP 8.7.3 lint cannot analyze Kotlin 2.3 metadata, which breaks the root build. Keep the tooling on major version 8 while moving AGP and the Gradle wrapper to the documented Kotlin 2.3-compatible line.\n\nCo-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@hyochan hyochan added automated Opened by scheduled automation fix Bug or build fix labels May 7, 2026
@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@coderabbitai

coderabbitai Bot commented May 7, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Rate limit exceeded

@hyochan has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 25 minutes and 25 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2bdf0dab-81ae-43a1-9225-f104889c153a

📥 Commits

Reviewing files that changed from the base of the PR and between 370bb31 and 17425d2.

📒 Files selected for processing (3)
  • clients/ios/DeeplineIOS/Sources/DeeplineAppModel.swift
  • clients/ios/DeeplineIOS/Sources/DeeplineServerClient.swift
  • clients/ios/DeeplineIOSUITests/DeeplineIOSUITests.swift
📝 Walkthrough

Walkthrough

The PR refactors iOS app state management to use idempotent helper methods that copy dictionaries before updates, adds accessibility labels to UI components, updates UI tests to align with app changes and permission handling, and upgrades Gradle and Android Gradle Plugin versions for the build system.

Changes

iOS App State Management and UI Updates

Layer / File(s) Summary
State Management Helpers
clients/ios/DeeplineIOS/Sources/DeeplineAppModel.swift
Added replaceMessages(_:for:) and replaceGroupMembers(_:for:) helpers that copy the relevant dictionary, update the target conversation key, and skip assignment when the value is already identical.
State Update Calls
clients/ios/DeeplineIOS/Sources/DeeplineAppModel.swift
loadMessages, WebSocket message handler, and loadGroupMembers now call the new helper methods instead of directly mutating messages and groupMembers dictionaries.
UI Enhancements
clients/ios/DeeplineIOS/Sources/RootView.swift
ChatInputBar send/voice button gets a conditional accessibility label ("Voice message" or "Send" based on draft text). MemberRow wraps user ID suffix in explicit String() conversion.
UI Test Updates
clients/ios/DeeplineIOSUITests/DeeplineIOSUITests.swift
testIdentitySetupAndLocalNotesChatAppears now registers a UI interruption monitor for "Notification permission", updates selectors to "Get Started", "Enter your name", and "e.g. iPhone 15 Pro", changes composer target to "Message" field, and verifies the updated accessibility labels.

Build System and Gradle Upgrades

Layer / File(s) Summary
Android Gradle Plugin Version
gradle/libs.versions.toml
Updated agp version reference from 8.7.3 to 8.13.2.
Gradle Wrapper Update
gradle/wrapper/gradle-wrapper.properties
Updated distributionUrl to Gradle 8.13 (from 8.10.2).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Hop hop, the state now flows with care,
No more direct mutations in the air,
Helpers guard against duplicate pain,
While tests and UI keep pace with the chain.
Gradle leaps forward—eight-thirteen awaits!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'fix(ci): restore Android lint compatibility' accurately describes the primary objective of the changeset: updating Android tooling versions to restore lint compatibility with Kotlin 2.3, which is the core issue being addressed.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/daily-build-green-2026-05-08

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@hyochan

hyochan commented May 7, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@hyochan

hyochan commented May 7, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

Handle the notification permission alert, follow the current setup labels, and expose the icon-only send action for UI automation.\n\nCo-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@hyochan

hyochan commented May 7, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

Avoid in-place mutations of actor-isolated ObservableObject dictionaries so the GitHub iOS CI runner on Xcode 15 can compile the app.

Co-Authored-By: OpenAI <codex@openai.com>
@hyochan

hyochan commented May 7, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

Convert the user-id suffix to String before interpolation so Swift 5.9 on the CI runner can compile RootView.

Co-Authored-By: OpenAI <codex@openai.com>
@hyochan

hyochan commented May 7, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

This was referenced May 7, 2026
@hyochan hyochan added codex Opened or maintained by Codex automation codex-automation Managed by scheduled Codex automation labels May 7, 2026
@hyochan hyochan self-assigned this May 7, 2026
@hyochan

hyochan commented May 7, 2026

Copy link
Copy Markdown
Member Author

Daily automation status: local quality sweep and E2E passed; GitHub iOS CI and crypto-boundary checks are now green on e78de74. Not auto-merging because Gemini is quota-blocked and CodeRabbit reported review skipped/rate-limited, so the configured bot review loop is incomplete.

@hyochan

hyochan commented May 8, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request updates the Android Gradle Plugin to 8.13.2 and Gradle to 8.13, while refactoring the iOS DeeplineAppModel to use helper methods for updating messages and group members. It also enhances accessibility in the chat input bar and updates UI tests to handle notification prompts and new UI labels. A review comment suggested adding an equality check in the message replacement helper to prevent redundant UI updates and potential flickering during polling.

Comment on lines +476 to +480
private func replaceMessages(_ newMessages: [DeeplineMessage], for conversationId: String) {
var updatedMessages = messages
updatedMessages[conversationId] = newMessages
messages = updatedMessages
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The replaceMessages helper is a valid workaround for the reported Xcode 15 compiler issues. However, since loadMessages is called frequently via a polling loop (every 3 seconds in ChatRoomView), this method will trigger a UI refresh even if the messages haven't changed. Adding an equality check here can prevent unnecessary view updates and potential flickering.

Suggested change
private func replaceMessages(_ newMessages: [DeeplineMessage], for conversationId: String) {
var updatedMessages = messages
updatedMessages[conversationId] = newMessages
messages = updatedMessages
}
private func replaceMessages(_ newMessages: [DeeplineMessage], for conversationId: String) {
guard messages[conversationId] != newMessages else { return }
var updatedMessages = messages
updatedMessages[conversationId] = newMessages
messages = updatedMessages
}

@hyochan

hyochan commented May 8, 2026

Copy link
Copy Markdown
Member Author

Bot review pass 1

  • Gemini reviewed current HEAD e78de74 and left one medium suggestion: add an equality guard in replaceMessages to avoid redundant SwiftUI refreshes during polling. Acknowledged; not blocking this build-restoration PR.
  • Copilot request failed with GitHub 422 because copilot-pull-request-reviewer is not a collaborator on this repository, so Copilot is treated as unavailable for this pass.
  • CodeRabbit still reports Review skipped / prior rate-limit output and has not produced a usable current-head review, so the automation is leaving this PR in waiting-bots.
  • Today's local Android E2E passed on main; local iOS E2E fails on main due the stale setup button label, which this PR already updates.

Skip replacing the message dictionary when polling returns the same message list, avoiding unnecessary SwiftUI refreshes while keeping the Xcode 15-safe assignment path.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@hyochan

hyochan commented May 8, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request refactors state management in DeeplineAppModel.swift by centralizing message and group member updates into dedicated helper methods, including a change detection guard for messages to prevent redundant UI updates. It also improves UI accessibility and string formatting in RootView.swift, updates UI tests to align with label changes and handle notification permissions, and bumps the Android Gradle Plugin and Gradle versions. A review comment suggests adding a similar change detection guard to the replaceGroupMembers method for consistency and performance optimization.

Comment on lines +483 to +487
private func replaceGroupMembers(_ members: [GroupMember], for conversationId: String) {
var updatedGroupMembers = groupMembers
updatedGroupMembers[conversationId] = members
groupMembers = updatedGroupMembers
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

For consistency with the replaceMessages implementation and to avoid redundant UI updates, consider adding a change detection guard here. Note that this requires GroupMember to conform to Equatable. Since GroupMember is a struct with all-equatable properties, it can easily be updated to conform, allowing for direct array comparison.

Suggested change
private func replaceGroupMembers(_ members: [GroupMember], for conversationId: String) {
var updatedGroupMembers = groupMembers
updatedGroupMembers[conversationId] = members
groupMembers = updatedGroupMembers
}
private func replaceGroupMembers(_ members: [GroupMember], for conversationId: String) {
guard groupMembers[conversationId] != members else { return }
var updatedGroupMembers = groupMembers
updatedGroupMembers[conversationId] = members
groupMembers = updatedGroupMembers
}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
clients/ios/DeeplineIOS/Sources/DeeplineAppModel.swift (1)

483-487: ⚡ Quick win

Add an equality guard in replaceGroupMembers to avoid redundant publishes.

replaceMessages already avoids no-op updates, but replaceGroupMembers always reassigns on Line 487 even when data is unchanged. This can cause avoidable SwiftUI refreshes.

Proposed patch
 private func replaceGroupMembers(_ members: [GroupMember], for conversationId: String) {
+    guard groupMembers[conversationId] != members else { return }
     var updatedGroupMembers = groupMembers
     updatedGroupMembers[conversationId] = members
     groupMembers = updatedGroupMembers
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@clients/ios/DeeplineIOS/Sources/DeeplineAppModel.swift` around lines 483 -
487, The replaceGroupMembers function currently always reassigns groupMembers
causing unnecessary publishes; modify replaceGroupMembers(_ members:
[GroupMember], for conversationId: String) to first compare the existing entry
groupMembers[conversationId] (or the whole groupMembers if nil) with the new
members and return early if they are equal, otherwise perform the update: only
assign groupMembers = updatedGroupMembers when the members differ to avoid no-op
updates and redundant SwiftUI refreshes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@clients/ios/DeeplineIOSUITests/DeeplineIOSUITests.swift`:
- Around line 52-53: Replace the timing-sensitive
XCTAssertTrue(app.buttons["Send"].exists) + app.buttons["Send"].tap() sequence
with a waitForExistence-based check: call
app.buttons["Send"].waitForExistence(timeout: <reasonableTimeout>) and assert
its return value (using XCTAssertTrue) before invoking tap() on that same button
(symbols: XCTAssertTrue, app.buttons["Send"], waitForExistence(timeout:),
tap()).

---

Nitpick comments:
In `@clients/ios/DeeplineIOS/Sources/DeeplineAppModel.swift`:
- Around line 483-487: The replaceGroupMembers function currently always
reassigns groupMembers causing unnecessary publishes; modify
replaceGroupMembers(_ members: [GroupMember], for conversationId: String) to
first compare the existing entry groupMembers[conversationId] (or the whole
groupMembers if nil) with the new members and return early if they are equal,
otherwise perform the update: only assign groupMembers = updatedGroupMembers
when the members differ to avoid no-op updates and redundant SwiftUI refreshes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0b9b3d31-6bd9-4b01-a33f-03b2cbeb9695

📥 Commits

Reviewing files that changed from the base of the PR and between a18facf and 370bb31.

📒 Files selected for processing (5)
  • clients/ios/DeeplineIOS/Sources/DeeplineAppModel.swift
  • clients/ios/DeeplineIOS/Sources/RootView.swift
  • clients/ios/DeeplineIOSUITests/DeeplineIOSUITests.swift
  • gradle/libs.versions.toml
  • gradle/wrapper/gradle-wrapper.properties

Comment thread clients/ios/DeeplineIOSUITests/DeeplineIOSUITests.swift Outdated
Avoid redundant group member refreshes and wait for the send action in the UI test so the build-restoration PR can complete the bot review loop cleanly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@hyochan

hyochan commented May 8, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces helper methods for updating messages and group members in the iOS app model, updates UI tests to match recent UI changes and handle notification permissions, and bumps Gradle and AGP versions. Feedback was provided regarding the performance of the dictionary update pattern in DeeplineAppModel.swift, suggesting a more efficient approach that avoids full dictionary copies while still addressing potential compiler issues.

Comment on lines +476 to +488
private func replaceMessages(_ newMessages: [DeeplineMessage], for conversationId: String) {
guard messages[conversationId] != newMessages else { return }
var updatedMessages = messages
updatedMessages[conversationId] = newMessages
messages = updatedMessages
}

private func replaceGroupMembers(_ members: [GroupMember], for conversationId: String) {
guard groupMembers[conversationId] != members else { return }
var updatedGroupMembers = groupMembers
updatedGroupMembers[conversationId] = members
groupMembers = updatedGroupMembers
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The 'copy-modify-assign' pattern used here is a known workaround for Xcode 15 compiler issues, but it results in a full dictionary copy on every update, which can impact performance as the number of conversations grows. Using direct subscript assignment within these helpers should still resolve the compiler's type inference issues while maintaining O(1) performance. Additionally, adding a comment explaining the workaround and using consistent parameter naming (e.g., newMembers) will improve maintainability.

    private func replaceMessages(_ newMessages: [DeeplineMessage], for conversationId: String) {
        // Workaround for Xcode 15 compiler issues with @Published dictionary updates
        guard messages[conversationId] != newMessages else { return }
        messages[conversationId] = newMessages
    }

    private func replaceGroupMembers(_ newMembers: [GroupMember], for conversationId: String) {
        // Workaround for Xcode 15 compiler issues with @Published dictionary updates
        guard groupMembers[conversationId] != newMembers else { return }
        groupMembers[conversationId] = newMembers
    }

@hyochan

hyochan commented May 8, 2026

Copy link
Copy Markdown
Member Author

Bot review pass 2

  • Addressed Gemini's previous message/group-member refresh suggestions in d7cc4e7.
  • Addressed CodeRabbit's UI-test flake suggestion by waiting for the Send button before tapping.
  • Gemini's latest direct-subscript suggestion is acknowledged but not applied: this PR intentionally keeps the copy-modify-assign path because direct mutation of @Published dictionaries was part of the Xcode 15 compatibility failure this branch fixes. The equality guards now avoid redundant refreshes while preserving that compatibility workaround.
  • Local validation on the latest head passed: iOS E2E, ./gradlew build --offline --quiet, and ./gradlew :shared:serverTest --offline --quiet.

@hyochan

hyochan commented May 8, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request refactors state updates in the iOS app model to prevent redundant changes, improves UI accessibility, and updates Gradle and AGP versions. Feedback focuses on improving the reliability of UI tests, specifically suggesting more robust handling of system notification alerts and recommending increased timeouts over conditional retry logic for button interactions.

app.launchEnvironment["DEEPLINE_SERVER_URL"] = "http://localhost:9091"
addUIInterruptionMonitor(withDescription: "Notification permission") { alert in
guard alert.buttons.count > 0 else { return false }
alert.buttons.element(boundBy: 0).tap()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Tapping the button at index 0 in a system alert is fragile and potentially incorrect for notification permissions. On iOS, the first button (index 0) is typically "Don't Allow", while the second button (index 1) is "Allow". If the application logic or subsequent tests depend on notifications being enabled, this will cause failures. It is more robust to identify the button by its label (e.g., alert.buttons["Allow"]) or use index 1 if the intent is to grant permission.

Comment on lines +25 to +27
if !displayNameField.waitForExistence(timeout: 3), setupButton.exists {
setupButton.tap()
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

This retry logic for tapping the setupButton is a sign of a flaky test environment. If the first tap at line 22 was successful but the transition is simply taking longer than 3 seconds, tapping the button again could lead to unexpected behavior or double-taps. A more reliable approach is to increase the timeout for the displayNameField.waitForExistence call at line 28 instead of performing a conditional second tap.

Keep the equality guards from review feedback while avoiding full dictionary copies inside the state update helpers.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@hyochan

hyochan commented May 9, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces helper methods in DeeplineAppModel to minimize redundant UI updates by checking for equality before modifying message and group member state. It also includes accessibility improvements, a fix for string interpolation in RootView, and updates to UI tests and build dependencies (Gradle and AGP). Feedback focuses on refining the equality checks in the new helper methods to treat nil and empty arrays as equivalent, preventing unnecessary refreshes when data is first initialized.

}

private func replaceMessages(_ newMessages: [DeeplineMessage], for conversationId: String) {
guard messages[conversationId] != newMessages else { return }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The current equality check will trigger a redundant @Published update when messages[conversationId] is nil and newMessages is an empty array. Since the UI (e.g., in ChatRoomView) treats nil and [] identically by defaulting to an empty list, you can avoid this unnecessary refresh by coalescing the current value to an empty array during comparison.

Suggested change
guard messages[conversationId] != newMessages else { return }
guard (messages[conversationId] ?? []) != newMessages else { return }

}

private func replaceGroupMembers(_ newMembers: [GroupMember], for conversationId: String) {
guard groupMembers[conversationId] != newMembers else { return }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Similar to replaceMessages, this check will trigger a redundant update if the current value is nil and the new members list is empty. Coalescing to an empty array here will prevent unnecessary UI refreshes when a conversation with no members is first loaded.

Suggested change
guard groupMembers[conversationId] != newMembers else { return }
guard (groupMembers[conversationId] ?? []) != newMembers else { return }

Handle notification permission prompts by intent, remove the setup double tap, and avoid nil-versus-empty refreshes in iOS model state helpers.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@hyochan

hyochan commented May 9, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request updates the project's build configuration by bumping Gradle and AGP versions. In the iOS client, it introduces helper methods to update messages and group members only when changes occur, preventing unnecessary UI re-renders. Additionally, it improves accessibility labels and updates UI tests to align with recent UI changes. Feedback was provided regarding the UI test interruption monitor, which is currently too broad and may inadvertently dismiss unexpected alerts, potentially leading to flaky test results.

Comment on lines +12 to +23
addUIInterruptionMonitor(withDescription: "Notification permission") { alert in
if alert.buttons["Allow"].exists {
alert.buttons["Allow"].tap()
} else if alert.buttons.count > 1 {
alert.buttons.element(boundBy: 1).tap()
} else if alert.buttons.count > 0 {
alert.buttons.element(boundBy: 0).tap()
} else {
return false
}
return true
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The addUIInterruptionMonitor implementation is quite broad as it attempts to tap any button labeled "Allow" or fallback to the first/second button available on any alert. While this works for the notification permission prompt, it might inadvertently dismiss other unexpected system or app alerts, potentially masking issues or causing flakiness in CI. Consider verifying the alert's title or message content to ensure only the intended permission prompt is handled.

Only handle notification permission alerts during the setup UI test so unexpected alerts remain visible to XCTest.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@hyochan

hyochan commented May 9, 2026

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request optimizes state updates in DeeplineAppModel by introducing helper methods that prevent redundant assignments to messages and group members, supported by adding Equatable conformance to GroupMember. It also improves accessibility in RootView, updates UI tests to handle notification permissions and new UI labels, and upgrades Gradle and the Android Gradle Plugin. I have no feedback to provide as no review comments were submitted.

@hyochan hyochan merged commit e3f428c into main May 9, 2026
5 checks passed
@hyochan hyochan deleted the fix/daily-build-green-2026-05-08 branch May 9, 2026 00:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

automated Opened by scheduled automation codex Opened or maintained by Codex automation codex-automation Managed by scheduled Codex automation fix Bug or build fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant