Skip to content

Fire Mode: Disable chat sync #8792

Open
0nko wants to merge 6 commits into
developfrom
feature/ondrej/fire-mode-disable-sync
Open

Fire Mode: Disable chat sync #8792
0nko wants to merge 6 commits into
developfrom
feature/ondrej/fire-mode-disable-sync

Conversation

@0nko

@0nko 0nko commented Jun 5, 2026

Copy link
Copy Markdown
Member

Task/Issue URL: https://app.asana.com/1/137249556945/project/1207418217763355/task/1215462571225879?focus=true

Description

Duck.ai chats may sync in Regular mode but must never sync in Fire mode.

A shared rule — BrowserMode.isSyncable gates the two places sync can start:

  • FEDuckChatJSHelper reports supportsAIChatSync as false in Fire mode. The Duck.ai FE reads this capability and doesn't offer or attempt sync (no "Turn On Sync & Backup"). browserMode is supplied per-surface by the calling tab / contextual sheet / standalone screen.
  • Native syncRealDuckChatSyncRepository's write methods (recordDuckAiChatsDeleted / recordSingleChatDeletion / recordSingleChatUpdate) no-op in a non-syncable mode, so Fire chat IDs never enter the pending sync queues. DuckChatSyncDataManager reads the @RegularMode store, so a background sync that fires during a Fire session still syncs Regular chats without touching Fire data.

Steps to test this PR

Prerequisites:

  • A device signed in to Sync with Duck.ai chat sync working in Regular mode (ideally a second synced device to confirm propagation)
  • fireTabs FF enabled in dev settings (needs a restart)

Regular mode still syncs (no regression)

  • In Regular mode with Sync enabled, create / edit / delete a Duck.ai chat
  • Verify it still propagates to the second device as before

Fire mode never syncs

  • Switch to Fire mode and open Duck.ai
  • Create / edit / delete Duck.ai chats in Fire mode
  • Verify nothing propagates to the second device

FE doesn't show sync options in Fire mode

  • Switch to Fire mode and open Duck.ai
  • Tap on the Chats icon
  • Tap on the Settings & More link
  • Select Duck.ai Settings
  • Verify Duck.ai does not show Sync & Backup option

UI Changes

Regular Fire
image image

Note

Medium Risk
Touches sync metadata writes and JS capability flags for privacy-sensitive Fire mode; scope is narrow and aligned with existing Regular-mode sync paths.

Overview
Prevents Duck.ai chats from syncing when the user is in Fire mode, while keeping sync behavior in Regular mode unchanged.

A shared BrowserMode.isSyncable rule (Fire → false, Regular → true) gates both entry points: DuckChatJSHelper now takes browserMode from each Duck.ai surface and only reports supportsAIChatSync when sync is enabled and the mode is syncable, so the web UI does not offer sync in Fire. RealDuckChatSyncRepository uses the same rule on deletion/update queue writers instead of a Fire-only check, so Fire chat activity never enters pending sync metadata.

Call sites (BrowserTabViewModel, contextual fragment, standalone web view) pass browserMode into JS processing; tests cover Fire config and the updated mocks.

Reviewed by Cursor Bugbot for commit 69eba25. Bugbot is set up for automated code reviews on this repo. Configure here.

0nko commented Jun 5, 2026

Copy link
Copy Markdown
Member Author

@0nko 0nko force-pushed the feature/ondrej/fire-mode-disable-sync branch from 234ebfa to e106f3f Compare June 9, 2026 13:58
@0nko 0nko force-pushed the feature/ondrej/fire-mode-duck-chats branch from 21054fb to 30246c3 Compare June 9, 2026 13:58
0nko added a commit that referenced this pull request Jun 9, 2026
The browser-mode simplification removed JsMessaging.browserMode, but the
Duck.ai sync handlers still read it via SyncFireModeGuard, breaking
:duckchat-impl compilation (and with it Build, JVM tests, and Lint).

Activity-scope the five sync handlers (Encrypt/Decrypt/SetUpSync/
SetAIChatHistoryEnabled/GetSyncStatus) and inject the host activity's
frozen BrowserMode, matching the native-storage handler. The guard now
operates on BrowserMode (renamed isFireMode() -> isSyncAvailable()).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
0nko added a commit that referenced this pull request Jun 11, 2026
The browser-mode simplification removed JsMessaging.browserMode, but the
Duck.ai sync handlers still read it via SyncFireModeGuard, breaking
:duckchat-impl compilation (and with it Build, JVM tests, and Lint).

Activity-scope the five sync handlers (Encrypt/Decrypt/SetUpSync/
SetAIChatHistoryEnabled/GetSyncStatus) and inject the host activity's
frozen BrowserMode, matching the native-storage handler. The guard now
operates on BrowserMode (renamed isFireMode() -> isSyncAvailable()).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@0nko 0nko force-pushed the feature/ondrej/fire-mode-disable-sync branch from 527eba6 to 4144e90 Compare June 11, 2026 09:30
@0nko 0nko force-pushed the feature/ondrej/fire-mode-duck-chats branch from 30246c3 to 3278b3d Compare June 11, 2026 09:30
0nko added a commit that referenced this pull request Jun 12, 2026
The browser-mode simplification removed JsMessaging.browserMode, but the
Duck.ai sync handlers still read it via SyncFireModeGuard, breaking
:duckchat-impl compilation (and with it Build, JVM tests, and Lint).

Activity-scope the five sync handlers (Encrypt/Decrypt/SetUpSync/
SetAIChatHistoryEnabled/GetSyncStatus) and inject the host activity's
frozen BrowserMode, matching the native-storage handler. The guard now
operates on BrowserMode (renamed isFireMode() -> isSyncAvailable()).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@0nko 0nko force-pushed the feature/ondrej/fire-mode-duck-chats branch from 3278b3d to 8f64f40 Compare June 12, 2026 19:14
@0nko 0nko force-pushed the feature/ondrej/fire-mode-disable-sync branch from 4144e90 to 31870cb Compare June 12, 2026 19:14
0nko added a commit that referenced this pull request Jun 12, 2026
The browser-mode simplification removed JsMessaging.browserMode, but the
Duck.ai sync handlers still read it via SyncFireModeGuard, breaking
:duckchat-impl compilation (and with it Build, JVM tests, and Lint).

Activity-scope the five sync handlers (Encrypt/Decrypt/SetUpSync/
SetAIChatHistoryEnabled/GetSyncStatus) and inject the host activity's
frozen BrowserMode, matching the native-storage handler. The guard now
operates on BrowserMode (renamed isFireMode() -> isSyncAvailable()).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@0nko 0nko force-pushed the feature/ondrej/fire-mode-duck-chats branch from 8f64f40 to 91cc1c8 Compare June 12, 2026 19:45
@0nko 0nko force-pushed the feature/ondrej/fire-mode-disable-sync branch from 31870cb to bdb5378 Compare June 12, 2026 19:45
0nko added a commit that referenced this pull request Jun 15, 2026
The browser-mode simplification removed JsMessaging.browserMode, but the
Duck.ai sync handlers still read it via SyncFireModeGuard, breaking
:duckchat-impl compilation (and with it Build, JVM tests, and Lint).

Activity-scope the five sync handlers (Encrypt/Decrypt/SetUpSync/
SetAIChatHistoryEnabled/GetSyncStatus) and inject the host activity's
frozen BrowserMode, matching the native-storage handler. The guard now
operates on BrowserMode (renamed isFireMode() -> isSyncAvailable()).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@0nko 0nko force-pushed the feature/ondrej/fire-mode-disable-sync branch from bdb5378 to cdee100 Compare June 15, 2026 09:40
@0nko 0nko force-pushed the feature/ondrej/fire-mode-duck-chats branch from 91cc1c8 to a79127d Compare June 15, 2026 09:40
0nko added a commit that referenced this pull request Jun 15, 2026
The browser-mode simplification removed JsMessaging.browserMode, but the
Duck.ai sync handlers still read it via SyncFireModeGuard, breaking
:duckchat-impl compilation (and with it Build, JVM tests, and Lint).

Activity-scope the five sync handlers (Encrypt/Decrypt/SetUpSync/
SetAIChatHistoryEnabled/GetSyncStatus) and inject the host activity's
frozen BrowserMode, matching the native-storage handler. The guard now
operates on BrowserMode (renamed isFireMode() -> isSyncAvailable()).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@0nko 0nko force-pushed the feature/ondrej/fire-mode-disable-sync branch from cdee100 to 61a4375 Compare June 15, 2026 10:11
@0nko 0nko force-pushed the feature/ondrej/fire-mode-duck-chats branch from a79127d to 677097c Compare June 15, 2026 10:11
0nko added a commit that referenced this pull request Jun 15, 2026
The browser-mode simplification removed JsMessaging.browserMode, but the
Duck.ai sync handlers still read it via SyncFireModeGuard, breaking
:duckchat-impl compilation (and with it Build, JVM tests, and Lint).

Activity-scope the five sync handlers (Encrypt/Decrypt/SetUpSync/
SetAIChatHistoryEnabled/GetSyncStatus) and inject the host activity's
frozen BrowserMode, matching the native-storage handler. The guard now
operates on BrowserMode (renamed isFireMode() -> isSyncAvailable()).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@0nko 0nko force-pushed the feature/ondrej/fire-mode-duck-chats branch from 31d8dd2 to e5cc923 Compare June 15, 2026 20:15
@0nko 0nko force-pushed the feature/ondrej/fire-mode-disable-sync branch from 61a4375 to 7c208af Compare June 15, 2026 20:15
@0nko 0nko requested a review from malmstein June 15, 2026 20:21
0nko added a commit that referenced this pull request Jun 16, 2026
The browser-mode simplification removed JsMessaging.browserMode, but the
Duck.ai sync handlers still read it via SyncFireModeGuard, breaking
:duckchat-impl compilation (and with it Build, JVM tests, and Lint).

Activity-scope the five sync handlers (Encrypt/Decrypt/SetUpSync/
SetAIChatHistoryEnabled/GetSyncStatus) and inject the host activity's
frozen BrowserMode, matching the native-storage handler. The guard now
operates on BrowserMode (renamed isFireMode() -> isSyncAvailable()).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@0nko 0nko force-pushed the feature/ondrej/fire-mode-disable-sync branch from 7c208af to b39544d Compare June 16, 2026 19:24
@0nko 0nko force-pushed the feature/ondrej/fire-mode-duck-chats branch from e5cc923 to e19c081 Compare June 16, 2026 19:24
@0nko 0nko mentioned this pull request Jun 16, 2026
4 tasks
@0nko 0nko force-pushed the feature/ondrej/fire-mode-duck-chats branch from e19c081 to 9b9a43f Compare June 18, 2026 08:11
@0nko 0nko force-pushed the feature/ondrej/fire-mode-disable-sync branch from b39544d to 95870fc Compare June 18, 2026 08:11
@0nko 0nko mentioned this pull request Jun 18, 2026
22 tasks
@0nko 0nko requested a review from CDRussell June 22, 2026 09:53
@CDRussell

Copy link
Copy Markdown
Member

@0nko , what's the plan for the duck chat UI re setting up sync. I can see it in the settings for instance, where it offers to Turn On Sync & Backup which will never work in a fire tab. Is there already a plan for the frontend UI to update around this (otherwise it's a confusing UX) ?

Screenshot_20260622_123848

@CDRussell

CDRussell commented Jun 22, 2026

Copy link
Copy Markdown
Member

@0nko Perhaps we're missing a tech design for how the FE should be handling fire tabs and syncing? I feel like this PR is rather reactive to discovering that fire tabs will need special considerations re sync and returning failures to all the API messages a bit of a blunt instrument.

What you've done in this PR is maybe only part of the story but not sufficient and we require other parts in place like the FE updating too.

0nko added a commit that referenced this pull request Jun 22, 2026
Task/Issue URL:
https://app.asana.com/1/137249556945/project/1207418217763355/task/1215444465437172?focus=true
Tech Design:
https://app.asana.com/1/137249556945/project/1207418217763355/task/1214570322752005?focus=true

### Description

This PR separates the native Duck.ai chat data layer between **Regular**
and **Fire** mode. Fire-mode chats are persisted in their own DB,
attachment directory, and WebView profile, so they never appear in
Regular chat history.

**Deviation from the tech design:** The `JsMessaging` interface change
was not needed.

The tech design proposed extending the shared `JsMessaging` interface to
thread the active `BrowserMode` through to the native-storage message
handler so it could select the correct per-mode store. That turned out
to be unnecessary:

- `DuckAiNativeStorageJsMessageHandler` resolves its backend via
`BrowserModeDataProvider<DuckAiBridgeStorage>.forMode(browserMode)`,
where `browserMode` is injected directly rather than passed through the
JS message
- The injected `BrowserMode` is the activity-frozen value (provided once
per activity by `provideActivityBrowserMode`, read from
`BrowserModeStateHolder.currentMode` at component creation). Because
switching mode recreates the activity, the one-mode-per-activity
invariant holds and the handler always reads the correct mode's storage
- To inject the activity-scoped `BrowserMode`, the native-storage
content-scope message handler plugin
(`DuckAiNativeStorageJsMessageHandler`) was moved from
`@ContributesMultibinding(AppScope::class)` to
`@ContributesMultibinding(ActivityScope::class)` because `BrowserMode`
is only bound in `ActivityScope`, not `AppScope`

**Note:** Sync is handled in a [subsequent
PR](#8792).

### Steps to test this PR

- [ ] Make sure `fireTabs` FF is enabled in dev settings (requires a
restart)
- [ ] In **Regular** mode, open Duck.ai and send a message (e.g.
`regular-test`); confirm it shows in Duck.ai chat history.
- [ ] Switch to **Fire** mode (tab switcher → mode toggle, or the "New
Fire Tab" menu item). Open Duck.ai chat history → `regular-test` is
**not** listed (Fire history is separate).
- [ ] In **Fire** mode, send a message (e.g. `fire-test`); it appears in
Fire history.
- [ ] Switch back to **Regular** → `fire-test` is **not** listed; only
`regular-test` is.


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **High Risk**
> Touches chat persistence, sync eligibility, and migration flags across
two databases; incorrect mode routing could leak Fire data into Regular
history or sync.
> 
> **Overview**
> Introduces **separate native Duck.ai persistence for Regular vs Fire
mode**: a second Room DB (`fire_mode_duck_ai.db`), attachment directory,
and `@RegularMode` / `@FireMode` qualified DAO bundles behind
`DuckAiBridgeStorage`, with `ModeAwareDuckAiChatStore` as the default
unqualified store that follows `BrowserModeStateHolder`.
> 
> **WebView / JS bridge:** `DuckAiNativeStorageJsMessageHandler` moves
to **ActivityScope**, resolves storage via injected activity-frozen
`BrowserMode` + `BrowserModeDataProvider`, and **ignores
`markMigrationDone` in Fire** so shared migration flags are not set from
ephemeral Fire sessions.
> 
> **Sync & privacy:** `RealDuckChatSyncRepository` **no-ops pending sync
metadata writes in Fire**; `DuckChatSyncDataManager` injects
**`@RegularMode` `DuckAiChatStore`** so background sync never reads Fire
chats. Internal debug server is Regular-only.
> 
> **UI:** `RealNativeInputStateStore` tracks the **selected tab for the
current mode** (not hard-coded Regular tabs). Tests updated/added across
store, sync, JS handler, and native input.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
9b9a43f. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Base automatically changed from feature/ondrej/fire-mode-duck-chats to develop June 22, 2026 19:14
@0nko 0nko force-pushed the feature/ondrej/fire-mode-disable-sync branch from 95870fc to 4abf6e5 Compare June 22, 2026 19:31

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4abf6e5. Configure here.

@0nko

0nko commented Jun 22, 2026

Copy link
Copy Markdown
Member Author

@CDRussell Thanks for the review!

Perhaps we're missing a tech design for how the FE should be handling fire tabs and syncing? I feel like this PR is rather reactive to discovering that fire tabs will need special considerations re sync and returning failures to all the API messages a bit of a blunt instrument.

Yeah, I agree the API responses everywhere might not have been the ideal solution.. I was trying to patch up all the places where I expected that Fire mode might be doing something with sync, so I was going overboard just to make sure nothing leaked. However, after going over the code again I realized that the only guards needed were actually a the write sites where chat IDs are added to the sync queue.

I can see it in the settings for instance, where it offers to Turn On Sync & Backup which will never work in a fire tab. Is there already a plan for the frontend UI to update around this (otherwise it's a confusing UX) ?

Good catch. I completely missed the fact that sync can be accessed outside the native settings. There's a parameter that tells the FE if the sync is available (already used by the sync FF), so now it's disabled in Fire mode.

Ready for another round.

@0nko 0nko requested a review from CDRussell June 22, 2026 19:54
0nko and others added 6 commits June 22, 2026 23:31
# Conflicts:
#	duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/sync/DuckChatSyncRepository.kt
The browser-mode simplification removed JsMessaging.browserMode, but the
Duck.ai sync handlers still read it via SyncFireModeGuard, breaking
:duckchat-impl compilation (and with it Build, JVM tests, and Lint).

Activity-scope the five sync handlers (Encrypt/Decrypt/SetUpSync/
SetAIChatHistoryEnabled/GetSyncStatus) and inject the host activity's
frozen BrowserMode, matching the native-storage handler. The guard now
operates on BrowserMode (renamed isFireMode() -> isSyncAvailable()).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
# Conflicts:
#	app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt
#	app/src/test/java/com/duckduckgo/app/browser/BrowserTabViewModelTest.kt
#	duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/helper/DuckChatJSHelper.kt
#	duckchat/duckchat-impl/src/test/kotlin/com/duckduckgo/duckchat/impl/helper/RealDuckChatJSHelperTest.kt
@0nko 0nko force-pushed the feature/ondrej/fire-mode-disable-sync branch from 706e37c to 69eba25 Compare June 22, 2026 21:31
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.

2 participants