2026-05-14 media-toolbox-kraken: план обновлён — unresolved 24→8, решения по документалкам, баги 1-6
This commit is contained in:
@@ -42,10 +42,8 @@ Eagle (10.99.0.2) ←→ wg0 VPS (10.99.0.1) ←→ wg1 VPS (10.99.1.1) ←→ K
|
||||
## Auto-connect на Eagle
|
||||
|
||||
`/usr/local/bin/wg-auto.sh` — следит за SSID через `WatchPaths` на `/Library/Preferences/SystemConfiguration/`:
|
||||
- SSID == `ASUS5` → `wg-quick down` (дома, Kraken в локалке... но сейчас Kraken не дома, поэтому VPN всегда нужен)
|
||||
- SSID != `ASUS5` → `wg-quick up`
|
||||
|
||||
> ⚠️ Пока Kraken не дома (не на ASUS5) — туннель нужен всегда, даже когда Eagle на ASUS5. Скрипт нужно будет пересмотреть если Kraken вернётся домой.
|
||||
- SSID == `ASUS5` → `wg-quick down` (дома, Kraken в локалке, туннель не нужен)
|
||||
- SSID != `ASUS5` → `wg-quick up` (вне дома, TM через VPN)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -42,74 +42,94 @@ media-pipeline (~/Developer/media_files_db, ветка kraken-agent)
|
||||
|
||||
---
|
||||
|
||||
## Текущий статус (2026-05-14)
|
||||
## Текущий статус (2026-05-14, сессия 5)
|
||||
|
||||
### Sync результаты (последний прогон)
|
||||
### Sync результаты
|
||||
| Категория | Папок | NFO | Статус |
|
||||
|-----------|-------|-----|--------|
|
||||
| movies | 127 | 127 | ✅ 100% |
|
||||
| series | 45 | 238 (эпизоды) | ✅ хорошо |
|
||||
| cartoons | 126 | ~30 | ⚠️ советские не резолвятся |
|
||||
| documentaries | 35 | ~5 | ⚠️ |
|
||||
| **Итого** | **317 regions** | **222 resolved** | **70%** |
|
||||
| series | 45 | ✅ | ✅ |
|
||||
| cartoons | 126 | ~119 | ✅ почти всё (8 через resolve-manual) |
|
||||
| documentaries | 35 | ~27 | ⚠️ 8 остались (см. ниже) |
|
||||
|
||||
### Что работает
|
||||
- ✅ Docker образ `media-pipeline:kraken` задеплоен (ветка `kraken-agent`)
|
||||
- ✅ `sync` корректно вызывается (был баг: двойное `media-pipeline media-pipeline`)
|
||||
- ✅ Кеш API-ответов: теперь `/config/cache` (persistent), 30-дневный TTL
|
||||
- ✅ Фильмы: 127/127 NFO
|
||||
- ✅ Сериалы: хорошо (Black Mirror, Queens Gambit, Good Omens и т.д.)
|
||||
- ✅ Сериалы: все resolved (Black Mirror, Ну погоди!, и др. — через resolve-manual)
|
||||
- ✅ Кеш API-ответов: `/config/cache`, 30-дневный TTL
|
||||
- ✅ Transmission download-complete hook установлен
|
||||
- ✅ `resolve-manual` работает (форс-резолв по TMDb/KP ID)
|
||||
- ✅ `resolve-manual` работает для movie/series/single-file
|
||||
|
||||
### Что не работает / в работе
|
||||
- ⚠️ **Советские мультики** — `bremenskie.muzykanty`, `budilnik`, `ёжик в тумане` и ~50 других не резолвятся автоматически. Legacy Go-код справлялся — нужно разобраться в чём разница
|
||||
- ⚠️ **Часть Disney/Pixar** в batch-режиме не проходят arbiter (Encanto, Lightyear, Inside Out) — одиночно через `resolve-manual` работают
|
||||
- 🔲 Jellyfin библиотеки — не настроены
|
||||
- 🔲 torrent-fix для 7 старых торрентов с путями `D:/Movies`
|
||||
- 🔲 Hermes cron на Кракене
|
||||
### Открытые задачи
|
||||
|
||||
#### 1. 🔴 Web search path для документалок и специфичного контента
|
||||
**Принятое решение:** ничто из библиотеки не должно оставаться в unresolved. Если TMDb/KP не находят — должен срабатывать web search (IMDb HTML scrape, Tier 4). Сейчас `webSearch.enabled=true` в config.json, но 8 документалок всё равно в unresolved.
|
||||
|
||||
**8 оставшихся:**
|
||||
- `/media/cartoons/25е - первый день`
|
||||
- `/media/documentaries/bbc. the real jungle book bear 2012`
|
||||
- `/media/documentaries/bbc. секреты собак`
|
||||
- `/media/documentaries/penguin meet the family (2020)`
|
||||
- `/media/documentaries/бегемоты - жизнь в воде`
|
||||
- `/media/documentaries/гиганты моря 2011`
|
||||
- `/media/documentaries/таинственная жизнь собак (hdtvrip 720p, 2013)`
|
||||
- `/media/documentaries/тайная жизнь собак (2016г)`
|
||||
|
||||
**Что нужно сделать:**
|
||||
- Запустить sync с `--debug` или отследить почему web search не помогает для этих item'ов
|
||||
- IMDbSearchProvider (Tier 4) должен находить BBC документалки по названию
|
||||
- Если IMDb тоже не находит — включить AIAgent (Tier 5) с OpenAI key, или добавить fallback: если все тиры вернули 0 кандидатов и папка содержит хотя бы один видеофайл → запускать web search по Google/IMDb с более агрессивными вариантами запроса
|
||||
- Цель: `unresolved.json` после sync = пустой
|
||||
|
||||
#### 2. 🟡 torrent-fix для 7 старых торрентов с путями `D:/Movies`
|
||||
- Transmission хранит old paths `D:/Movies/...` — нужен `torrent-fix` subcommand
|
||||
|
||||
#### 3. 🟡 Jellyfin библиотеки
|
||||
- Настроить библиотеки в Jellyfin (http://192.168.1.14:8096)
|
||||
- NFO файлы готовы, Jellyfin должен их подхватить
|
||||
|
||||
#### 4. 🟢 Hermes cron на Кракене
|
||||
- Периодический запуск sync (новые загрузки через Transmission)
|
||||
|
||||
---
|
||||
|
||||
## Принятые решения (архитектурные)
|
||||
|
||||
| Решение | Описание |
|
||||
|---------|----------|
|
||||
| **Unresolved = 0** | Цель — ничто из библиотеки не должно оставаться в unresolved после sync. Web search (Tier 4) и AI agent (Tier 5) — последние резервы перед тем как считать item нераспознанным |
|
||||
| **Web search enabled** | `providers.webSearch.enabled=true` в config.json. IMDb scrape как Tier 4 для всего, что не нашли TMDb/KP |
|
||||
| **Документалки приоритет KP** | BBC/Discovery документалки плохо индексированы в TMDb. KP часто знает их под русскими названиями. Стратегия: сначала KP с русским названием из папки, потом IMDb |
|
||||
| **resolve-manual** | Только для экстренных случаев, не как регулярный процесс |
|
||||
| **Single-file NFO** | Для `.mkv`/`.m4v` файлов NFO создаётся рядом (`film.nfo`), не внутри |
|
||||
|
||||
---
|
||||
|
||||
## Исправленные баги
|
||||
|
||||
### Баг 1: Двойной вызов binary (КРИТИЧЕСКИЙ)
|
||||
**Проблема:** `docker run ... media-pipeline:kraken media-pipeline sync` — бинарь получал `media-pipeline` как первый аргумент = неизвестный subcommand → general help. Все прошлые dry-run не работали.
|
||||
**Фикс:** `ENTRYPOINT ["media-pipeline"]` → правильный вызов `docker run ... sync ...`
|
||||
`docker run ... media-pipeline:kraken media-pipeline sync` → бинарь получал `media-pipeline` как аргумент.
|
||||
**Фикс:** `ENTRYPOINT ["media-pipeline"]`
|
||||
|
||||
### Баг 2: TitleSimilarity — симметричный Jaccard
|
||||
**Проблема:** `encanto_2021_bdrip_by_dalemake` vs `Encanto`: `lengthRatio = 1/5 = 0.2` → confidence ≈ 0.05 → rejected. Noise-токены (bdrip, 1080p, год) убивали матч.
|
||||
**Фикс:** Asymmetric scoring — когда query длиннее candidate, переключаемся на candidate-coverage Jaccard (покрытие кандидата запросом). `lengthRatio = 1.0` когда query длиннее.
|
||||
**Коммит:** `2704ce3`
|
||||
`encanto_2021_bdrip_by_dalemake` vs `Encanto`: lengthRatio=0.2 → rejected.
|
||||
**Фикс:** Asymmetric scoring — candidate-coverage Jaccard когда query длиннее. Коммит `2704ce3`
|
||||
|
||||
### Баг 3: ProviderSearchStrategy.maxCallsPerRun = 8
|
||||
**Проблема:** 8 API-вызовов на провайдер → 192 из 200 items никогда не искались.
|
||||
### Баг 3: maxCallsPerRun = 8
|
||||
8 API-вызовов → 192/200 items никогда не искались.
|
||||
**Фикс:** 8 → 500. Коммит `2704ce3`
|
||||
|
||||
### Баг 4: Series-гипотезы для одиночных файлов
|
||||
**Проблема:** `NumberedEpisodesHypothesisStrategy` и `NamedEpisodesHypothesisStrategy` генерировали series-гипотезы для одиночных `.avi`/`.mkv` без S/E маркеров → TMDb искал по `/search/tv` вместо `/search/movie`.
|
||||
Одиночные `.avi`/`.mkv` без S/E маркеров получали series-гипотезу → TMDb искал по `/search/tv`.
|
||||
**Фикс:** `videos.count < 2 && !hasAnyEpisodeMarkers → return nil`. Коммит `17c2ddc`
|
||||
|
||||
### Баг 5: HTTP кеш не персистился
|
||||
**Проблема:** `cacheDirectory = /usr/local/bin/cache` внутри контейнера. `docker run --rm` → кеш удалялся при каждом запуске → тысячи дублирующих API запросов.
|
||||
**Фикс:** Autodetect `/config` mount → `/config/cache` (persistent volume). Коммит `5a1053c`
|
||||
`cacheDirectory = /usr/local/bin/cache` — удалялся при `docker run --rm`.
|
||||
**Фикс:** Autodetect `/config` mount → `/config/cache`. Коммит `5a1053c`
|
||||
|
||||
---
|
||||
|
||||
## Следующий шаг: советские мультики
|
||||
|
||||
**Задача:** понять почему `bremenskie.muzykanty`, `budilnik 1984`, `ёжик в тумане` и ~50 других советских мультиков не резолвятся, хотя легаси Go-код справлялся.
|
||||
|
||||
**Гипотезы:**
|
||||
1. Транслитерация → KP не ищет по Latin `bremenskie` → нужна Cyrillic варианты в query
|
||||
2. NameTokenization не генерирует качественную обратную транслит для советских названий
|
||||
3. KP API возвращает результаты, но TitleSimilarity не матчит (разные скрипты)
|
||||
4. TMDb `dual` search по `bremenskie muzykanty` → нет результатов → нужен только KP
|
||||
|
||||
**Что делать:**
|
||||
- Проверить что именно возвращает KP для `bremenskie muzykanty`
|
||||
- Проверить что variant'ы генерирует NameTokenization для этих файлов
|
||||
- Если проблема в transliteration accuracy — починить в TitleSimilarity (cross-script fuzzy match)
|
||||
### Баг 6: resolve-manual NFO path для single-файлов
|
||||
`resolve-manual` писал NFO внутрь файла вместо рядом.
|
||||
**Фикс:** Detect `isDirectory`, для файлов → `deletingPathExtension().appendingPathExtension("nfo")`. Коммит `c0fdc59`
|
||||
|
||||
---
|
||||
|
||||
@@ -119,7 +139,7 @@ media-pipeline (~/Developer/media_files_db, ветка kraken-agent)
|
||||
/srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/docker/media-pipeline/
|
||||
├── config.json ← TMDb/KP ключи, Transmission RPC, directories
|
||||
├── unresolved.json ← реестр нераспознанных (создаётся автоматически)
|
||||
├── cache/ ← HTTP кеш 30 дней (после фикса)
|
||||
├── cache/ ← HTTP кеш 30 дней
|
||||
└── on-download-complete.sh
|
||||
```
|
||||
|
||||
@@ -152,6 +172,7 @@ docker run --rm ... media-pipeline:kraken \
|
||||
| Transmission | http://192.168.1.14:9091 |
|
||||
| Исходники | `~/Developer/media_files_db/`, ветка `kraken-agent` |
|
||||
| Docker образ | `media-pipeline:kraken` (arm64, Colima 24GB) |
|
||||
| kraken-ssh | `ssh kraken-ssh` → 10.99.1.2:22 через WireGuard (обновлено 2026-05-14) |
|
||||
|
||||
---
|
||||
|
||||
@@ -160,4 +181,5 @@ docker run --rm ... media-pipeline:kraken \
|
||||
- **2026-05-13 сессия 1:** HTPC разбужен, rsync запущен (~1.3TB), торрент-база импортирована (128 торрентов)
|
||||
- **2026-05-13 сессия 2:** Docker build arm64, deploy на Кракен, first sync
|
||||
- **2026-05-13 сессия 3:** `kraken-agent` ветка: UnresolvedStore, resolve-manual, agent, torrent-fix subcommands
|
||||
- **2026-05-14 сессия 4:** Найдены и исправлены 5 системных багов (см. выше). Sync: 222/317 resolved. Кеш починен.
|
||||
- **2026-05-14 сессия 4:** 5 системных багов исправлены. Sync: 222/317 resolved (70%).
|
||||
- **2026-05-14 сессия 5:** resolve-manual для 13 items (movies/cartoons/series/documentaries). unresolved: 24 → 8. Исправлен баг NFO path для single-файлов. kraken-ssh переключён на WireGuard.
|
||||
|
||||
@@ -1,83 +1,229 @@
|
||||
# iOS: Chat-Path Onboarding — Tracker Blocking Demo
|
||||
|
||||
> **Asana:** [Ship Review task](https://app.asana.com/1/137249556945/task/1214147157456478)
|
||||
> **Asana:** [Ship Review task 1214147157456478](https://app.asana.com/1/137249556945/task/1214147157456478)
|
||||
> **Branch stack:** `demo-tracker-blocking-onboarding` → `ui-polish` → `chat-path-dialog-polish` → `sr-feedback` → `uti-flow`
|
||||
> **Due:** 2026-05-15
|
||||
|
||||
---
|
||||
|
||||
## PR Stack
|
||||
|
||||
| PR | Branch | Status |
|
||||
| PR | Branch | Base | Review status |
|
||||
|---|---|---|---|
|
||||
| [#4544](https://github.com/duckduckgo/apple-browsers/pull/4544) | `demo-tracker-blocking-onboarding` | `main` | Open — review required (Alessandro + Rachel left comments) |
|
||||
| [#4591](https://github.com/duckduckgo/apple-browsers/pull/4591) | `demo-tracker-blocking-onboarding-ui-polish` | #4544 | Approved |
|
||||
| [#4664](https://github.com/duckduckgo/apple-browsers/pull/4664) | `demo-tracker-blocking-onboarding-chat-path-dialog-polish` | #4591 | Approved |
|
||||
| [#4855](https://github.com/duckduckgo/apple-browsers/pull/4855) | `demo-tracker-blocking-onboarding-sr-feedback` | #4664 | Open — no review yet. Has uncommitted local changes (see below). |
|
||||
| [#4668](https://github.com/duckduckgo/apple-browsers/pull/4668) | `demo-tracker-blocking-onboarding-uti-flow` | ? | Open — no review yet. Has open Bugbot + reviewer comments (see below). |
|
||||
|
||||
---
|
||||
|
||||
## Uncommitted Local Changes — PR #4855 branch (`sr-feedback`)
|
||||
|
||||
All of the following are in the working tree but **NOT committed or pushed**. They must be committed before #4855 can be reviewed or merged.
|
||||
|
||||
### 1. `NewTabPageViewController.swift` — setBarsHidden + delegate pattern + loading guard
|
||||
|
||||
**What changed:**
|
||||
- Replaced `(parent as? MainViewController)?.setChatPathVisitSiteControlsLocked(true/false)` + `chromeDelegate?.setNavigationBarHidden(true/false)` with a single `chromeDelegate?.setBarsHidden(true/false, animated: false, customAnimationDuration: nil)` call.
|
||||
- Removed all `(parent as? MainViewController)?` casts from `NewTabPageViewController`.
|
||||
- Loading guard (`guard ... isLoading != true else { return }`) was a standalone guard that would abort dialog presentation entirely, leaving an orphaned `hostingController` reference. Folded into the outer `if` condition using the new delegate method instead.
|
||||
- `dismiss()` now calls `setBarsHidden(false)` when `didHideBarsForChatPathVisitSiteDialog` is true.
|
||||
|
||||
**Why `setChatPathVisitSiteControlsLocked` calls were removed:**
|
||||
Alessandro's review comment on [#4855 line 280](https://github.com/duckduckgo/apple-browsers/pull/4855) asked to use `NewTabPageControllerDelegate` instead of casting `(parent as? MainViewController)`. A separate review comment on [#4855 line 477](https://github.com/duckduckgo/apple-browsers/pull/4855) noted Costas's preference to hide both address bar and toolbar via `setBarsHidden(false)`. Using `setBarsHidden` via `chromeDelegate` removes the need for the cast entirely, making `setChatPathVisitSiteControlsLocked` unreachable. The method definition still exists in `MainViewController+DuckAIExperiment.swift:166` as dead code — needs to be deleted.
|
||||
|
||||
**Source:** Alessandro review comments on PR #4855 ([line 280](https://github.com/duckduckgo/apple-browsers/pull/4855), [line 473](https://github.com/duckduckgo/apple-browsers/pull/4855), [line 477](https://github.com/duckduckgo/apple-browsers/pull/4855)) + Costas's preference cited therein + Bugbot #4855 "Guard early return aborts entire dialog" + Bugbot #4855 "Navigation bar not restored when NTP dismissed".
|
||||
|
||||
**Current state:** ✏️ Uncommitted local change on `sr-feedback` branch.
|
||||
|
||||
### 2. `NewTabPageControllerDelegate.swift` + `MainViewController.swift` — new delegate method
|
||||
|
||||
**What changed:** Added `newTabPageControllerCurrentTabIsLoading(_ controller: NewTabPageViewController) -> Bool` to the `NewTabPageControllerDelegate` protocol. Implemented in `MainViewController.swift` to return `currentTab?.isLoading == true`.
|
||||
|
||||
**Source:** Alessandro review comment on [#4855 line 473](https://github.com/duckduckgo/apple-browsers/pull/4855): "should we add `(parent as? MainViewController)?.currentTab?.isLoading != true` as condition of the if instead of having the guard..." Also addresses Bugbot #4855 "Guard early return aborts entire dialog presentation" and removes the `(parent as?)` cast as requested on [#4855 line 280](https://github.com/duckduckgo/apple-browsers/pull/4855).
|
||||
|
||||
**Current state:** ✏️ Uncommitted local change on `sr-feedback` branch.
|
||||
|
||||
### 3. `OnboardingIntroViewModel.swift` — returning-user guard + remove hardcoded cohort override
|
||||
|
||||
**What changed:**
|
||||
- Uncommented `guard case .introDialog(isReturningUser: false) = introSteps.first` in `insertExperimentStepIfNeeded()`. This ensures sync-restore / returning users are excluded from the Duck.ai query experiment step.
|
||||
- Removed hardcoded `return .treatmentB` override from `resolveDuckAIQueryExperimentCohortID()` (was left in for local testing).
|
||||
|
||||
**Source (returning-user guard):** [Alessandro May 7 review on PR #4544](https://github.com/duckduckgo/apple-browsers/pull/4544), Asana task [1214682678629767](https://app.asana.com/1/137249556945/task/1214682678629767), Bugbot on #4855 "Returning-user guard commented out despite PR intent". The guard was temporarily commented out during development; it must be active before shipping.
|
||||
|
||||
**Source (hardcoded override removal):** Bugbot on #4855 "Hardcoded debug return bypasses feature flag entirely". This was a local testing override (`return .treatmentB`) that must not ship.
|
||||
|
||||
**Current state:** ✏️ Uncommitted local change on `sr-feedback` branch.
|
||||
|
||||
### 4. `UserText.swift` + all 26 lproj files — `searchAndDuckAIOption` string reverted + "Ask AI" toggle label
|
||||
|
||||
**What changed:**
|
||||
- `searchAndDuckAIOption` reverted to `"Toggle between\nSearch and Duck.ai"` (was changed to "Toggle between\nSearch and Ask AI" in a prior commit).
|
||||
- DuckAIQuery screen toggle label changed from "Duck.ai" to "Ask AI" in `OnboardingView+DuckAIExperimentSearchContent.swift`.
|
||||
|
||||
**Source (revert):** Alessandro review comment on [#4855 UserText.swift:2375](https://github.com/duckduckgo/apple-browsers/pull/4855): *"the rename of 'Duck.ai' to 'Ask AI' is for the toggle we show in the Duck Ai Query screen. The copy for this screen should be reverted."* — meaning the Search Experience screen copy stays as "Duck.ai", only the DuckAI query toggle label becomes "Ask AI".
|
||||
|
||||
**Source (Ask AI label):** [GJ8 ship review](https://app.asana.com/1/137249556945/task/1214147157456478): *"change 'Duck.ai' to 'Ask AI' in the toggle screen in onboarding only."*
|
||||
|
||||
⚠️ **Unresolved copy question:** Alessandro's comment says "Ask.ai" (with dot). Gary's GJ8 says "Ask AI" (no dot). Needs explicit confirmation from product/design before shipping.
|
||||
|
||||
**Current state:** ✏️ Uncommitted local change on `sr-feedback` branch.
|
||||
|
||||
### 5. Dead code: `setChatPathVisitSiteControlsLocked` in `MainViewController+DuckAIExperiment.swift:166`
|
||||
|
||||
**What:** The method has no callers now that `NewTabPageViewController` uses `setBarsHidden` via the chrome delegate instead. Should be deleted.
|
||||
|
||||
**Source:** Removal of callers in item #1 above.
|
||||
|
||||
**Current state:** ✏️ Still in code, needs deletion. Uncommitted.
|
||||
|
||||
---
|
||||
|
||||
## Open GitHub Comment Threads — PR #4544
|
||||
|
||||
These Bugbot threads were on PR #4544 and are **not resolved on GitHub**. Status of each:
|
||||
|
||||
### [Bugbot] Hardcoded return forces all users into treatment group (OnboardingIntroViewModel.swift)
|
||||
**Issue:** `return .treatmentA` hardcoded override in `resolveDuckAIQueryExperimentCohortID()`.
|
||||
**Code state:** The `.treatmentA` override was removed on the `#4544` branch (replaced with `.treatmentB` for testing, then also removed — see uncommitted change #3 above). The `#4544` branch tip no longer has `.treatmentA` hardcoded.
|
||||
**Thread state:** 🔴 **Not resolved on GitHub.** Bugbot comment was on an old commit — outdated. → Resolve thread.
|
||||
|
||||
### [Bugbot] Subscription promo override always returns true (OnboardingSubscriptionPromotionHelper.swift)
|
||||
**Issue:** `shouldDisplay` was hardcoded to `return true` for testing.
|
||||
**Code state:** Reverted in commit [`f8d5ba2`](https://github.com/duckduckgo/apple-browsers/commit/f8d5ba2) on #4544 branch.
|
||||
**Thread state:** 🔴 **Not resolved on GitHub.** Fix is in the branch. → Resolve thread.
|
||||
|
||||
### [Bugbot] Chat-path subscription redirect commented out, variable unused (RebrandedNewTabDaxDialogFactory.swift)
|
||||
**Issue:** `isChatPathSubscriptionPromo` was commented out, variable unused.
|
||||
**Code state:** Dead code removed in commit [`e682475`](https://github.com/duckduckgo/apple-browsers/commit/e682475) on #4544 branch.
|
||||
**Thread state:** 🔴 **Not resolved on GitHub.** Fix is in the branch. → Resolve thread.
|
||||
|
||||
### [Bugbot] Missing pixel definitions (PixelEvent.swift:2120)
|
||||
**Issue:** `onboardingChatPathTryVisitSiteUnique` and `onboardingChatPathTrackersBlockedUnique` missing from `PixelEvent`.
|
||||
**Code state:** Both defined in commit [`ec42fd8`](https://github.com/duckduckgo/apple-browsers/commit/ec42fd8) on #4544 branch (lines 268–269, 2119–2120 of PixelEvent.swift).
|
||||
**Thread state:** 🔴 **Not resolved on GitHub.** Fix is in the branch. → Resolve thread.
|
||||
|
||||
### [Bugbot] Chat-path completion dialog shown twice (MainViewController.swift:4711)
|
||||
**Issue:** Two competing paths (`tabDidRequestNewTab` dispatch + direct call) could both invoke `presentChatPathOnboardingCompletionIfNeeded()`.
|
||||
**Code state:** `presentChatPathOnboardingCompletionIfNeeded()` is guarded by `chatPathPhase == .trackerToEOJ`. Whether the double-call race was fully resolved needs verification.
|
||||
**Thread state:** 🔴 **Not resolved on GitHub.** → Verify code, then resolve thread.
|
||||
|
||||
### [Bugbot r3234645543] Chat-path EOJ not shown after tapping tracker dialog CTA (TabViewController.swift:4214)
|
||||
**Issue:** `didTapDismissContextualOnboardingAction` doesn't call `tabDidRequestNewTab` for chat path, so tapping "Got it" on tracker dialog doesn't open a new tab for the EOJ.
|
||||
**Code state:** 🔴 **NOT fixed on the #4544 branch.** The fix (`if chatPathPhase == .trackerToEOJ { tabDidRequestNewTab }` in `didTapDismissContextualOnboardingAction`) exists only on the `sr-feedback` branch (commit `6c3774e4f8`). It will be present when the full PR stack merges, but it is not in #4544 itself.
|
||||
**Thread state:** 🔴 **Not resolved on GitHub.** Fix is not in this PR — it's in #4855. Note this in the thread or backport the fix to #4544.
|
||||
|
||||
---
|
||||
|
||||
## Open GitHub Comment Threads — PR #4664
|
||||
|
||||
### [Alessandro + Bugbot] Title changes for all paths, not just chat path (RebrandedNewTabDaxDialogFactory.swift)
|
||||
**Issue:** `createSubsequentDialog` title was changed for all flows, not gated on `isChatPath`.
|
||||
**Code state:** Fixed — `isChatPath` check added (`daxDialogsFlowCoordinator.chatPathPhase == .visitSite`). The rebranded factory now uses the chat-path title conditionally.
|
||||
**Thread state:** Likely resolved by the fix but confirm on GitHub. → Check and resolve thread.
|
||||
|
||||
### [Bugbot] Dismiss button appears on standard path too (RebrandedContextualOnboardingDialogs+SubscriptionPromo.swift:101)
|
||||
**Issue:** Dismiss button added for chat path appeared on standard path too.
|
||||
**Code state:** Needs verification on #4664 branch.
|
||||
**Thread state:** 🔴 **Not confirmed resolved.** → Verify code.
|
||||
|
||||
---
|
||||
|
||||
## Open GitHub Comment Threads — PR #4668
|
||||
|
||||
### [aataraxiaa] Commented-out `Config(...)` line in FeatureFlag.swift:635
|
||||
**Issue:** `// Config(source: .remoteReleasable(.subfeature(AIChatSubfeature.unifiedToggleInput)))` — a dead commented-out duplicate still in code.
|
||||
**Source:** [aataraxiaa review comment](https://github.com/duckduckgo/apple-browsers/pull/4668): *"Obviously you just changed this for testing, but just a reminder to change it back before we merge."*
|
||||
**Code state:** 🔴 **Still in code** on `#4668` branch. The `defaultValue: .enabled` override + commented-out original are both present.
|
||||
**Thread state:** 🔴 **Not resolved.** → Remove the commented-out line and the `defaultValue: .enabled` before merging.
|
||||
|
||||
### [Bugbot] Hardcoded debug return bypasses cohort resolution (OnboardingIntroViewModel.swift:473)
|
||||
**Issue:** Same `return .treatmentB` override as above.
|
||||
**Code state:** Removed in the uncommitted local change on `sr-feedback` branch. Will be present once committed and the stack is built. Not yet fixed on #4668 branch itself.
|
||||
**Thread state:** 🔴 **Not resolved.** → Will be resolved when sr-feedback is merged down or the fix is backported.
|
||||
|
||||
### [Bugbot] Protocol method `embedInUnifiedInputEditingAreaIfActive` never called (MainViewController.swift + BrowserChromeManager.swift)
|
||||
**Issue:** Method added to `BrowserChromeDelegate` protocol and implemented in `BrowserChromeManager`, but never called anywhere.
|
||||
**Code state:** On the `sr-feedback` branch, commit `82bb0f71e3` removed the `embedDialogInEditingState` dead code path. The method may now be truly unreachable. Needs verification on #4668 branch.
|
||||
**Thread state:** 🔴 **Not resolved.** → Verify, then either add a caller or delete the method and its implementations.
|
||||
|
||||
---
|
||||
|
||||
## Open GitHub Comment Threads — PR #4855
|
||||
|
||||
All four Alessandro review comments and all Bugbot comments are addressed by the **uncommitted local changes** listed above. The GitHub threads are **not yet resolved** because the changes haven't been committed/pushed.
|
||||
|
||||
| Comment | Fix location | Thread resolved? |
|
||||
|---|---|---|
|
||||
| [#4544](https://github.com/duckduckgo/apple-browsers/pull/4544) | `demo-tracker-blocking-onboarding` | Open — review required |
|
||||
| [#4591](https://github.com/duckduckgo/apple-browsers/pull/4591) | `demo-tracker-blocking-onboarding-ui-polish` | Approved |
|
||||
| [#4664](https://github.com/duckduckgo/apple-browsers/pull/4664) | `demo-tracker-blocking-onboarding-chat-path-dialog-polish` | Approved |
|
||||
| [#4668](https://github.com/duckduckgo/apple-browsers/pull/4668) | `demo-tracker-blocking-onboarding-uti-flow` | Open — no review yet |
|
||||
| [#4855](https://github.com/duckduckgo/apple-browsers/pull/4855) | `demo-tracker-blocking-onboarding-sr-feedback` | Open — no review yet |
|
||||
| Use `NewTabPageControllerDelegate` instead of `(parent as?)` cast (line 280) | Uncommitted — `NewTabPageControllerDelegate.swift` | 🔴 No |
|
||||
| Hide both bars via `setBarsHidden` per Costas (line 477) | Uncommitted — `NewTabPageViewController.swift` | 🔴 No |
|
||||
| Fold loading check into `if` condition (line 473) | Uncommitted — `NewTabPageViewController.swift` | 🔴 No |
|
||||
| Revert `searchAndDuckAIOption` copy (UserText.swift:2375) | Uncommitted — `UserText.swift` + lproj files | 🔴 No |
|
||||
| Bugbot: Navigation bar not restored when NTP dismissed (line 281) | Uncommitted — `NewTabPageViewController.swift` `dismiss()` | 🔴 No |
|
||||
| Bugbot: Guard early return aborts dialog presentation (line 473) | Uncommitted — guard folded into `if` | 🔴 No |
|
||||
| Bugbot: Hardcoded debug return bypasses feature flag (OnboardingIntroViewModel:473) | Uncommitted — hardcoded return removed | 🔴 No |
|
||||
| Bugbot: Returning-user guard commented out (OnboardingIntroViewModel:451) | Uncommitted — guard uncommented | 🔴 No |
|
||||
|
||||
→ **Commit and push all local changes first. Then resolve these threads.**
|
||||
|
||||
---
|
||||
|
||||
## Required Changes
|
||||
## Pre-Ship Blockers
|
||||
|
||||
### PR #4544
|
||||
- [x] Danger CI: no `@UserDefaultsWrapper` remains
|
||||
- [x] Mock refactor (alessandroboron): `MockDaxDialogsSettings.chatPathPhase` plain stored property
|
||||
- [x] **Sync restore exclusion** — [Alessandro May 7](https://app.asana.com/1/137249556945/task/1214147157456478): *"if the user selects 'Restore My Stuff' we disable Dax dialogs — we should not enrol those users in the experiment"*. Fixed: uncommented `guard case .introDialog(isReturningUser: false) = introSteps.first` in `insertExperimentStepIfNeeded()`
|
||||
- [x] `return .treatmentA` override removed from `resolveDuckAIQueryExperimentCohortID()`
|
||||
- [x] Pixels: `onboardingChatPathTryVisitSiteUnique` / `onboardingChatPathTrackersBlockedUnique` defined, no overlap with PR #4687
|
||||
### 1. Commit and push local changes on `sr-feedback`
|
||||
|
||||
### PR #4664
|
||||
- [x] Title scope fix (alessandroboron): `createSubsequentDialog` uses correct title per chat-path vs standard path
|
||||
All changes in the "Uncommitted Local Changes" section above must be committed to `alex/demo-tracker-blocking-onboarding-sr-feedback` and pushed before PR #4855 can be reviewed. Then the eight GitHub threads above can be resolved.
|
||||
|
||||
### PR #4668
|
||||
- [x] Dialog position, dismiss, UTI bar, completion path resolved
|
||||
- [x] `.unifiedToggleInput` feature flag has no hardcoded `defaultValue: .enabled`
|
||||
**Current state:** 🔴 Not done.
|
||||
|
||||
### PR #4855
|
||||
- [x] `setBarsHidden(true/false, animated: false, customAnimationDuration: nil)` replaces `setNavigationBarHidden` + `setChatPathVisitSiteControlsLocked` in show/dismiss/dismissHostingController
|
||||
- [x] `newTabPageControllerCurrentTabIsLoading` added to `NewTabPageControllerDelegate`; all `(parent as? MainViewController)?` casts gone from `NewTabPageViewController`
|
||||
- [x] Loading guard folded into outer `if` via delegate method
|
||||
- [x] `searchAndDuckAIOption` reverted to `"Toggle between\nSearch and Duck.ai"` in `UserText.swift` + all 26 lproj files
|
||||
- [x] **DuckAIQuery toggle copy** — [Gary May 6](https://app.asana.com/1/137249556945/task/1214147157456478): *"change 'Duck.ai' to 'Ask AI' in the toggle screen in onboarding only, not the standard toggle"*. Fixed: `DuckAIQueryExperiment.toggleAILabel = "Ask AI"` (uses `NotLocalizedString`)
|
||||
### 2. Tell UTI team the experiment name
|
||||
|
||||
**Source:** [Pete Apr 30 comment](https://app.asana.com/1/137249556945/task/1214147157456478/1214600831548835): Pete's team will exclude users enrolled in this experiment from the UTI feature rollout, to avoid breaking their onboarding. They need the final experiment name.
|
||||
|
||||
**Current state:** 🔴 Blocked — experiment name not final (see #4 below). Once known: fill into [O-J <> O-N Coordination](https://app.asana.com/1/137249556945/project/1214157224317277/task/1214288645859692) and [O-N Live Onboarding Experiment Details](https://app.asana.com/1/137249556945/task/1214601039604921).
|
||||
|
||||
### 3. Privacy config: add US/EN targeting to override
|
||||
|
||||
**Source:** [Task 1214682678629768](https://app.asana.com/1/137249556945/task/1214682678629768): experiment must be limited to US English users. Without this, all locales worldwide would be enrolled.
|
||||
|
||||
**What:** In `privacy-configuration/overrides/ios-override.json`, add `"targets": [{ "localeLanguage": "en", "localeCountry": "US" }]` to the experiment entry.
|
||||
|
||||
**Current state:** 🔴 Local edit exists on wrong branch (`alex/remove-autocomplete-tabs`) in the `privacy-configuration` repo, not committed.
|
||||
|
||||
### 4. Privacy config: rename the experiment
|
||||
|
||||
**Source:** [Task 1214682678629768](https://app.asana.com/1/137249556945/task/1214682678629768): some internal users were enrolled under `onboardingDuckAIQueryExperiment` during testing. A new name gives production users a clean, separate enrollment.
|
||||
|
||||
**What — three-part change:**
|
||||
1. **BSK** (`SharedPackages/BrowserServicesKit`): add a new case to `AIChatSubfeature` enum with the new name string.
|
||||
2. **App** (`iOS/Core/FeatureFlag.swift`): update `FeatureFlag.onboardingDuckAIQueryExperiment` to reference the new subfeature case.
|
||||
3. **`privacy-configuration` repo** (`overrides/ios-override.json`): add new experiment entry with `targets`, and set the old `onboardingDuckAIQueryExperiment` entry to `"state": "disabled"`.
|
||||
|
||||
Do this in the same PR as item #3 (both touch the same file in the same repo).
|
||||
|
||||
**Current state:** 🔴 Blocked — new experiment name not decided.
|
||||
|
||||
### 5. Fix commented-out feature flag line in PR #4668
|
||||
|
||||
**Source:** aataraxiaa review comment on #4668 (see Open Threads above).
|
||||
|
||||
**What:** Remove `defaultValue: .enabled` and the `// Config(...)` dead line from `FeatureFlag.swift:635` for `unifiedToggleInput`.
|
||||
|
||||
**Current state:** 🔴 Still in code on `#4668` branch. Not fixed.
|
||||
|
||||
### 6. Clarify "Ask AI" vs "Ask.ai" copy
|
||||
|
||||
**Source:** Conflict between GJ8 ("Ask AI") and Alessandro's review comment ("Ask.ai").
|
||||
|
||||
**Current state:** 🔴 Implemented as "Ask AI" (no dot) per GJ8. Awaiting explicit product/design confirmation.
|
||||
|
||||
---
|
||||
|
||||
## Before Going Live
|
||||
## Experiment Config (current, local override)
|
||||
|
||||
### 1. UTI experiment exclusion
|
||||
|
||||
**Source:** [Pete Apr 30, ship review](https://app.asana.com/1/137249556945/task/1214147157456478/1214600831548835): *"to avoid impacting any live onboarding experiments we can exclude those experiment participants when we release. Continue coordination in [O-J <> O-N Coordination](https://app.asana.com/1/137249556945/project/1214157224317277/task/1214288645859692)."*
|
||||
|
||||
Task [O-J <> O-N Coordination](https://app.asana.com/1/137249556945/project/1214157224317277/task/1214288645859692) (owned by Pete) lists O-N experiments the UTI team needs to be aware of for exclusion at UTI rollout. Already lists this iOS experiment under "iOS - O-N will handle".
|
||||
|
||||
- [ ] Confirm experiment is listed and named correctly in [O-J <> O-N Coordination](https://app.asana.com/1/137249556945/project/1214157224317277/task/1214288645859692) before going live.
|
||||
|
||||
### 2. Privacy config targeting
|
||||
|
||||
- [x] Added `"targets": [{ "localeLanguage": "en", "localeCountry": "US" }]` to `onboardingDuckAIQueryExperiment` in `privacy-configuration/overrides/ios-override.json`
|
||||
|
||||
### 3. Experiment rename
|
||||
|
||||
No explicit Asana comment or PR review requested this — no source found.
|
||||
|
||||
- [ ] **Decide:** rename `onboardingDuckAIQueryExperiment` before production rollout? If yes: requires new `AIChatSubfeature` case in BSK + new privacy config entry + disable old one.
|
||||
|
||||
---
|
||||
|
||||
## Resolved / Dismissed
|
||||
|
||||
- **GJ6c** — No longer required; address bar hidden for visit-site step; Gary + Costas confirmed search after trackers-blocked is acceptable
|
||||
- **GJ2** — X button removed from chat-path dialogs (PR #4664)
|
||||
- **GJ3** — Address bar + toolbar hidden for visit-site step (chat-path only)
|
||||
- **GJ4** — Copy: "Next, try visiting a site!" after AI
|
||||
- **GJ7** — Returning users excluded from experiment enrollment
|
||||
- **GJ8** — Onboarding toggle shows "Ask AI"; Search Experience screen keeps "Duck.ai"
|
||||
- **Fire tabs flash** — Suppressed via `isStillOnboarding()` in `DaxDialogs`
|
||||
|
||||
---
|
||||
|
||||
## Experiment Config (current)
|
||||
|
||||
Entry in `privacy-configuration/overrides/ios-override.json` under `aiChat` subfeatures:
|
||||
`privacy-configuration/overrides/ios-override.json` under `aiChat` subfeatures:
|
||||
|
||||
```json
|
||||
"onboardingDuckAIQueryExperiment": {
|
||||
@@ -91,5 +237,5 @@ Entry in `privacy-configuration/overrides/ios-override.json` under `aiChat` subf
|
||||
}
|
||||
```
|
||||
|
||||
> Feature flag: `FeatureFlag.onboardingDuckAIQueryExperiment`
|
||||
> Feature flag: `FeatureFlag.onboardingDuckAIQueryExperiment` in `iOS/Core/FeatureFlag.swift`
|
||||
> Cohort type: `FeatureFlag.DuckAIQueryExperimentCohort`
|
||||
|
||||
Reference in New Issue
Block a user