Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 80 additions & 35 deletions design-qa.md
Original file line number Diff line number Diff line change
@@ -1,56 +1,101 @@
# Dream Report Design QA
# Browser Migration Layout Regression QA

**Source visual truth path**
## Source visual truth

`/Users/moonrailgun/Library/Application Support/Open Design/namespaces/release-stable/data/projects/d7969910-805f-49b3-9d34-80d6d21d2420/dream-recap-redesign.html`
- User-reported broken state: `/var/folders/0l/4dc990md3yn_g3b46dtmhp880000gn/T/orca-paste-1786372826229-081b4a4d-c6af-4262-8884-3f09e49acc37.png`
- Source pixels: 1940 x 1610.
- State: dark theme, migration step 2, category selection screen.

**Implementation screenshot path**
## Implementation evidence

Unavailable. The required in-app browser is not available in this session, and the project cannot produce a fresh Dao binary because the shared generated Chromium checkout fails normal import on 15 unrelated Settings patches before compilation begins.
- Browser-rendered screenshot: `/var/folders/0l/4dc990md3yn_g3b46dtmhp880000gn/T/orca-computer-use/1c00cbd7-8d01-4d07-b35d-db9c98d4b199-screenshot.png`
- Before/after comparison: `/tmp/dao-import-layout-before-after.png`
Comment on lines +5 to +12

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Replace machine-local artifact paths.

The report links to /var/folders/... and /tmp/... files that other reviewers and CI cannot access. Store required screenshots as repository-relative artifacts or attach them through the supported QA artifact system, and reference stable paths.

Also applies to: 65-73

🤖 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 `@design-qa.md` around lines 5 - 12, Replace the machine-local screenshot
references in the design-qa report with repository-relative artifact paths or
supported QA attachment references. Update both the user-reported broken-state
path and the implementation-evidence comparison path, while preserving the
documented screenshot context.

- Window viewport: 1398 x 909 CSS pixels at device scale factor 2.
- Implementation pixels: 2796 x 1818.
- State: dark theme, `dao://import`, Google Chrome selected, migration step 2, all supported categories selected.

**Viewport and normalization**
## Full-view comparison evidence

- Intended comparison viewport: 1440 x 1000 CSS pixels.
- Source: live responsive HTML; no fixed raster pixel dimensions or device scale factor.
- Implementation: no browser-rendered pixels available, so density normalization could not be performed.
- State: history route with the latest completed daily report selected.
The pre-fix capture shows the first completed progress segment stretched vertically through the header, making the header consume most of the shell. The post-fix browser capture shows the intended compact header, four horizontal progress segments, the category list inside the scrollable main region, and the persistent footer at the bottom of the shell.

**Full-view comparison evidence**
The source and implementation captures use different crops, so the comparison image normalizes both to 900 pixels high while preserving aspect ratio. The comparison is used for the layout regression rather than pixel-level typography matching.

Blocked. The source artifact was inspected directly as HTML/CSS/JS and its selected layout tokens were mapped into `dao_dream_app.ts`, but a source screenshot and browser-rendered implementation screenshot could not be placed into a same-viewport comparison.
## Focused region comparison evidence

**Focused region comparison evidence**
The header and progress rail are clearly readable in the full-view comparison, so a separate crop was not needed. The affected progress segment changed from approximately 390 CSS pixels tall to the intended 4 CSS pixels tall. The header no longer inherits completion-view sizing.

Blocked for the same reason. The regions requiring focused comparison are the annual activity heatmap, compact history rows, report header, TL;DR card, rhythm slots, theme cards, statistic strip, memory candidates, and full-report disclosure.
## Required fidelity surfaces

**Primary interactions checked**
- Fonts and typography: unchanged by the fix; hierarchy, weights, wrapping, and localized copy remain consistent with the existing implementation.
- Spacing and layout rhythm: passed; the header, scrollable main region, and footer return to their intended three-row shell layout.
- Colors and visual tokens: unchanged; the existing dark theme and Dao accent tokens remain intact.
- Image quality and asset fidelity: unchanged; existing browser logos remain sharp and correctly scaled.
- Copy and content: unchanged; localized step, category, authorization tip, and action copy remain present.

- The complete WebUI suite passes: 61 test files and 728 tests, including daily and weekly report loading, shared history selection, 53-week heatmap rendering, structured and legacy recaps, measured rhythm buckets, rerun, copy-image states, confirmation-gated habit persistence, non-destructive rejection, source-domain exclusion, debug metadata, loading, empty, and error states.
- Browser interaction and console-error checks are unavailable without a browser-rendered fresh build.
## Primary interactions and console checks

**Findings**
- Selected the Google Chrome source and advanced to step 2 in the rebuilt Dao Debug application.
- Confirmed category toggles, password authorization tip, Back action, and Start action remain visible.
- No import WebUI error appeared in debug stderr. Repeated Touch ID keychain entitlement diagnostics are unrelated to this layout change.

- [P1] Browser-rendered visual fidelity is unverified.
- Location: complete `dao://dream` history route.
- Evidence: no implementation screenshot exists for same-viewport comparison.
- Impact: typography, final computed spacing, dark mode, and Chromium WebUI rendering cannot be accepted visually from source and jsdom tests alone.
- Fix: restore the shared Chromium import baseline, run `npm run rebuild`, launch the debug app, capture `dao://dream/` at 1440 x 1000, and compare it against a same-size capture of the Open Design artifact.
## Findings and comparison history

**Implementation checklist**
- Iteration 1 — P1 fixed: `.done` was shared by completed progress segments and the completion view. The generic completion selector applied `min-height: 390px` and flex-column sizing to the rail segment.
- Fix: renamed the completion-view class to `.completion`, leaving `.rail span.done` as the progress-state selector.
- Post-fix evidence: the focused regression test reports no 390px minimum height on the completed segment, and the rebuilt browser capture shows a compact horizontal rail.

- [x] Match the Open Design two-column desktop structure and responsive stack.
- [x] Use real report history for activity cells and report selection.
- [x] Add structured summary, rhythm, themes, statistics, memory candidates, and folded markdown.
- [x] Preserve rerun, share, exclusions, debug, loading, empty, and error behavior.
- [x] Support legacy markdown-only reports.
- [ ] Complete browser-rendered same-viewport visual comparison and console check.
## Verification

**Comparison history**
- Focused import WebUI tests: 7 passed.
- Full WebUI suite: 64 files and 776 tests passed.
- Lit reactive-field lint: 205 files scanned, 0 violations.
- `npm run rebuild`: succeeded in 16 incremental steps.
- `git diff --check`: passed.

- Iteration 1: source implementation review completed from the Open Design artifact; all 728 WebUI tests passed; visual comparison blocked before the first screenshot pair because no fresh implementation could be rendered.
No actionable P0, P1, or P2 visual findings remain for this regression.

**Follow-up polish**
final result: passed

- Reassess small-screen statistic-label wrapping and 53-week heatmap scroll position after a real browser capture.
---

final result: blocked
# Browser Migration Failure And Logo QA

## Source visual truth

- User-reported completion state: `/var/folders/0l/4dc990md3yn_g3b46dtmhp880000gn/T/orca-paste-1786445140695-69467f1b-dea4-4e72-98ff-929e65e28a19.png`.
- User-reported broken logo state: `/var/folders/0l/4dc990md3yn_g3b46dtmhp880000gn/T/orca-paste-1786445925493-926fcbbe-e275-4e0b-84e5-da3196959779.png`.
- State: light theme, partial migration completion and source selection.

## Implementation evidence

- Completion screenshot: `/tmp/dao-import-ui-qa-completion-final.png`.
- Migration screenshot: `/tmp/dao-import-ui-qa-progress-final.png`.
- Before/after completion comparison: `/tmp/dao-import-ui-qa-comparison-final.png`.
- Viewport: 894 x 672 CSS pixels at device scale factor 2.
- Screenshot pixels: 1788 x 1344.

## Comparison evidence

The completion state now lists failed categories in a compact danger-tinted summary and repeats the failure state on the affected statistic cards. Successful categories retain the existing neutral card treatment and all imported counts remain visible. The header and migration target use the packaged Dao product logo; the selected source uses its browser-specific logo.

The runtime image checks reported a 64 x 64 natural size for each Dao logo and a 150 x 150 natural size for the Microsoft Edge logo. No image had a zero natural size or rendered as a broken image.

## Required fidelity surfaces

- Typography: passed; existing hierarchy and localized copy are preserved.
- Spacing and layout: passed; the new failure summary fits without overlapping the statistics or footer.
- Colors: passed; failed categories use a restrained danger treatment while successful categories remain neutral.
- Asset fidelity: passed; same-origin WebUI resource mapping serves the packaged Dao logo and source-browser SVGs remain crisp.
- Content clarity: passed; the failed category names and `Migration failed` status are both visible.

## Verification

- Focused WebUI and browser-import contract tests: 2 files, 15 tests passed.
- Lit reactive-field lint: 205 files scanned, 0 violations.
- `npm run rebuild`: succeeded in 11 incremental steps after correcting the resource header.
- `git diff --check`: passed.
- Runtime `dao://import` image and failure-state inspection: passed.

No actionable P0, P1, or P2 visual findings remain for this change.

final result: passed
14 changes: 14 additions & 0 deletions docs/feature-checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,19 @@ Lightweight popup window form factor.
> `_little_dao_external.mm.patch`) — apply order matters. Two patches edit
> `startup_browser_creator_impl.cc` (`_impl` then `_little_dao`).

## 6.1 Browser Data Migration

| ✔ | Feature | Source / patch | Risk | Verify after upgrade |
|---|---------|----------------|------|----------------------|
| ☐ | Source-profile detection | `browser/import/dao_source_detector.*`, Chromium `ImporterList` bridge | 🟡 | Separate detected Chrome, Arc, Edge, Safari, and Firefox profiles remain enabled and expose only categories available on the current platform; browser kinds without a detected profile remain visible as disabled cards; when all kinds are unavailable, the empty explanation and rescan action remain visible and Continue stays disabled |
| ☐ | Asynchronous candidate counts | `browser/import/dao_chromium_profile_adapter.*`, `dao_migration_service.*`, `dao_import_ui.*`, `resources/import/` | 🟡 | Selecting Chrome, Arc, or Edge starts per-category counts without blocking Continue; password counts do not trigger Keychain; tab counts operate on a temporary snapshot; switching sources ignores late results from the previous profile; Safari and Firefox show unavailable; final imported totals remain authoritative |
| ☐ | Stable local snapshots | `browser/import/dao_profile_snapshot.*` | 🟡 | With the source browser open, files and SQLite sidecars retry on metadata changes; session directories copy recursively; cancellation removes the temporary directory; cleanup stays off the UI thread and blocks browser shutdown until sensitive snapshots are removed |
| ☐ | Category-isolated job lifecycle | `browser/import/dao_migration_job.*`, `dao_migration_service.*` | 🟡 | A failed or denied password import does not stop bookmarks/history/tabs/extensions; partial completion lists every failed category and marks its result card while preserving its imported count; reload reconnects without replacing the active source snapshot; retry selects failed categories only; cancel stops at a batch boundary, retains completed counts, and never renders as success |
| ☐ | Merge-only target writes | `browser/import/dao_chromium_migration_target.*`, `dao_legacy_profile_writer.*` | 🔴 | Existing bookmark paths, passwords, open tab URLs, and installed extensions remain unchanged; conflicts are counted instead of overwritten; history/password success is reported only after destination verification |
| ☐ | Imported tab folder | `dao_chromium_migration_target.*`, `dao_sidebar_ui.*`, `dao_sidebar_app.ts` | 🔴 | Imported tabs preserve order, remain cancellable between bounded batches, are background/discarded, appear in one collapsed folder, roll back if folder persistence fails, and notify every same-profile sidebar after success |
| ☐ | Extension reinstall boundary | `dao_chromium_profile_adapter.*`, `dao_chromium_migration_target.*` | 🔴 | Only web-store entries are queued, prompts are sequential, disabled source extensions remain disabled, and extension local data/sign-ins are not copied |
| ☐ | Password authorization notice | `resources/import/dao_import_app.ts`, `dao_strings.grd` | 🟢 | Selecting passwords shows the Keychain tip before Start; denying the prompt marks only passwords as needing attention |

## 7. `dao://` Scheme & WebUI Routing

The compatibility layer that lets both `dao://` (canonical) and `chrome://` (legacy) work.
Expand All @@ -196,6 +209,7 @@ The compatibility layer that lets both `dao://` (canonical) and `chrome://` (leg
| ☐ | Omnibox virtual URL shows `dao://` | `content/browser/renderer_host/navigation_controller_impl.cc.patch` | 🟡 | `chrome://settings` displays as `dao://settings` |
| ☐ | Register both factories (PDF/component-ext subresources) | `chrome/browser/chrome_content_browser_client.cc.patch` (**zeroed diff index — apply by context**) | 🔴 | PDF isn't a blank page |
| ☐ | Register Dao WebUI controllers | `webui/chrome_web_ui_configs.cc.patch`, `chrome_web_ui_controller_factory.cc.patch` | 🟡 | Dao pages load |
| ☐ | Standalone browser migration WebUI | `dao_import_ui.*`, `resources/import/`, `resources/settings/dao_page/dao_page.{html,ts}.patch`, `ui/chrome_pages.cc.patch`, `webui/chrome_web_ui_configs.cc.patch`, `chrome_paks.gni.patch` | 🟡 | **You and Dao** shows an **Import browser data** row; both that row and the system **Import Bookmarks and Settings…** command open `dao://import`; the browser tab uses the localized **Import browser data** title; source and destination migration nodes use the selected browser and packaged Dao product logos; the page loads without console errors and reload reconnects to an active job |
| ☐ | WebUI default CSP allows both schemes | `ui/webui/webui_util.cc.patch` | 🔴 | **Diff upstream's new CSP host list — every new `chrome://` host needs a `dao://` mirror or resources silently break** |
| ☐ | `chrome://newtab` → `dao://welcome`; reverse rewriter | `chrome/browser/browser_about_handler.cc.patch` | 🔴 | NTP lands on welcome; omnibox shows `dao://`; reverse rewriter still registered |
| ☐ | URL fixer treats chrome/dao as equivalent | `components/url_formatter/url_fixer.cc.patch` | 🟢 | Omnibox fixup accepts both |
Expand Down
58 changes: 58 additions & 0 deletions docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,64 @@ macOS-style floating control center panel bundling extensions and utilities.
- **Menu item + command handling** — User can reopen anytime
- **First-run preference tracking** — Auto-opens only on first launch (managed via `dao_pref_names`)

## 6.1 Browser Data Migration

- **Standalone migration surface** — `dao://import` is a dedicated Lit WebUI,
with a localized **Import browser data** document title for its browser tab,
exposed as an explicit **Import browser data** row on the **You and Dao**
Settings page and from the existing system **Import Bookmarks and Settings…**
command instead of Chromium's modal importer. Its source grid always shows
Chrome, Arc, Edge, Safari, and Firefox: detected profiles remain individually
selectable, while browser kinds without a detected profile appear as disabled
cards. The flow lets the user choose supported data categories, reconnects to
an active profile-scoped job after reload, and reports per-category progress
and retryable partial failures. Stopped jobs retain completed-batch counts and
are presented as cancelled, not completed. Partial completion identifies the
categories that need retrying in a dedicated summary and visually marks their
result cards without hiding any items that were imported before the failure.
The active migration rail uses the detected source browser's product logo and
Dao's packaged product logo instead of generic letter placeholders.
- **Asynchronous candidate counts** — Selecting a Chromium-family profile
starts independent background counts for each supported category without
blocking navigation or migration. Bookmark, history, password, and extension
counts read source metadata directly; password counting never decrypts a
credential or triggers Keychain authorization. Tab sessions are counted only
from a temporary snapshot because Chromium's session reader can rotate files.
These preflight values describe scanned candidates and may differ from final
imported totals if the source changes or Dao skips conflicts. Legacy Safari
and Firefox importers report the count as unavailable until migration.
- **Supported sources** — Chrome, Arc, and Edge profiles use Dao's snapshot
adapters; Safari and Firefox profiles use Chromium's sandboxed platform
importers for the categories those importers support on macOS.
- **Safe source reads** — Chromium-family stores are copied to a temporary
profile snapshot with bounded metadata-stability retries. SQLite sidecars and
session directories are included, so source browsers can normally remain
open. Temporary snapshots are deleted with the category operation. Cleanup
stays off the UI thread and blocks browser shutdown until copied history,
password, and session data has been removed.
- **Merge-only destination writes** — Bookmarks are placed under a localized
imported root, destination password conflicts are preserved, already-open
tab URLs and installed extensions are skipped, and history writes use the
profile History service. History and password counts advance only after the
destination services confirm the persisted records. No category replaces
existing Dao data.
- **Passwords and extensions** — The selection screen warns that password
decryption may trigger a macOS Keychain authorization prompt. A denial fails
only passwords. Compatible web-store extensions are reinstalled in sequence;
extension storage and sign-in state are not copied.
Comment on lines +380 to +389

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

澄清扩展跳过条件。

Line 382 says “installed extensions are skipped”, while Line 388 says compatible web-store extensions are reinstalled. Specify that extensions already installed in the destination are skipped. Keep source web-store extensions eligible for sequential reinstallation.

🤖 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 `@docs/features.md` around lines 380 - 389, Clarify the “Merge-only destination
writes” documentation to state that extensions already installed in the
destination are skipped. Keep the “Passwords and extensions” description
explicit that compatible source web-store extensions remain eligible for
sequential reinstallation.

- **Imported tabs** — Source session tabs retain order, become background
discarded tabs, and are collected in a collapsed sidebar folder. Tabs are
created in cancellable batches; a failed folder write rolls back tabs from
that import instead of leaving orphaned browser tabs. Successful folder
persistence invalidates every live same-profile sidebar cache.
- **Privacy boundary** — Migration records, snapshots, and progress stay local;
only official extension reinstallation may use the network. Cookies are not
imported because Chromium does not expose a safe cross-profile cookie import
API and copied encrypted cookie stores are not portable.
- Core owners: `browser/import/dao_migration_service.*`,
`dao_profile_snapshot.*`, source adapters and target writers;
`webui/dao_import_ui.*` and `webui/resources/import/` own the WebUI.

## 7. Little Dao Window

Lightweight window form factor for popups / mini-tools.
Expand Down
26 changes: 26 additions & 0 deletions scripts/commands/__tests__/browser_import_contract.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import fs from 'node:fs';
import path from 'node:path';

import {describe, expect, it} from 'vitest';

const repoRoot = path.resolve(import.meta.dirname, '../../..');

function readDaoSource(relativePath: string): string {
return fs.readFileSync(path.join(repoRoot, relativePath), 'utf8');
}

describe('browser import ownership contract', () => {
it('blocks browser shutdown until snapshot cleanup is complete', () => {
const header = readDaoSource(
'src/dao/browser/import/dao_profile_snapshot.h',
);
const implementation = readDaoSource(
'src/dao/browser/import/dao_profile_snapshot.cc',
);

expect(header).toContain('base::OnTaskRunnerDeleter');
expect(implementation).toMatch(
/CreateSequencedTaskRunner\(\s*\{base::MayBlock\(\),[\s\S]*?base::TaskShutdownBehavior::BLOCK_SHUTDOWN\}/,
);
});
});
Loading
Loading