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
108 changes: 35 additions & 73 deletions design-qa.md
Original file line number Diff line number Diff line change
@@ -1,94 +1,56 @@
# Android Design QA
# Dream Report Design QA

## Sources
**Source visual truth path**

- Open Design HTML authority: `newtab.html`, `browsing.html`, `settings.html`, `history.html`, `bookmarks.html`, `downloads.html`, and `extensions.html`.
- Tokens and behavior: `DESIGN-TOKENS.md`, `HANDOFF.md`, and `ACCEPTANCE.md`.
- Exported visual reference: `image.png`.
- Desktop brand authority: the borderless `branding/dao_logo.png` source artwork.
- Runtime captures: API 34 Pixel 6 emulator at 1080 x 2400 in light and dark themes.
`/Users/moonrailgun/Library/Application Support/Open Design/namespaces/release-stable/data/projects/d7969910-805f-49b3-9d34-80d6d21d2420/dream-recap-redesign.html`

Comment on lines +3 to 6

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

移除本机绝对路径和用户名。

该路径公开了 moonrailgun 本机用户名。其他开发者也无法访问该路径。请改用仓库内受版本控制的相对路径,或使用不含个人标识符的设计制品访问说明。

🤖 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 3 - 6, Remove the personal absolute filesystem
path from the “Source visual truth path” section in design-qa.md and replace it
with a repository-relative path to the version-controlled design artifact, or a
non-personal instruction for accessing the artifact without exposing a username.

## Comparison
**Implementation screenshot path**

The exported new-tab reference and the emulator capture were normalized to the same canvas and inspected side by side. The Android implementation keeps the neutral palette, typography hierarchy, mark, greeting, pill search field, spacing rhythm, and icon treatment. Android system bars replace the prototype device frame as required.
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.

The exported reference contains an overlap between the search pill and greeting. The implementation follows the newer acceptance requirement instead: the greeting and search field have clear separation at the target viewport.
**Viewport and normalization**

The borderless desktop artwork was rendered beside the API 34 launcher and new-tab captures. The Android adaptive icon keeps the complete ink-circle Dao mark inside the system safe zone, and the new-tab page uses the transparent original without cropping, a macOS frame, or a replacement text glyph.
- 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.

## Findings and fixes
**Full-view comparison evidence**

- P0: none.
- P1 fixed: new-tab greeting/search overlap.
- P1 fixed: focusing the editable text field now activates the animated search state.
- P1 fixed: browsing drawer order now matches the acceptance list exactly.
- P1 fixed: dark-theme status and navigation bar icons now use a readable light appearance after launch and focus changes.
- P2 fixed: Material 3 download progress stop indicator removed to match the simple prototype bar.
- P2 fixed: localized resource collision for the active-download section label removed.
- P2 fixed: placeholder `N` tile and macOS-specific framed icon replaced by the canonical borderless Dao artwork in both launcher and in-app surfaces.
- P2 fixed: scanner entry uses the requested Lucide `ScanLine` glyph instead of the generic `Scan` glyph.
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.

## Interaction checks
**Focused region comparison evidence**

- Search field docks to the top and exposes recent or filtered suggestions.
- Query matching is case-insensitive, limited to five results, and highlights the matching text.
- Scanner overlay opens, animates, and closes.
- Address submission loads a real GeckoView page.
- Right drawer opens from the address bar and closes through the scrim or back action.
- History search, bookmark segment, download pause, and extension switches update locally.
- Dark mode updates immediately and persists through Preferences DataStore across force-stop and relaunch.
- Launcher and new-tab branding remain legible at their rendered sizes without clipping the ink-circle mark.
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.

## Tab-count refinement — 2026-08-04
**Primary interactions checked**

- Source visual truth: `/var/folders/0l/4dc990md3yn_g3b46dtmhp880000gn/T/orca-paste-1785776258694-95491411-83d3-4a0b-a16d-d41a4793d627.png` plus the explicit instruction to remove the count from expanded search and use a tighter Chrome-style frame elsewhere.
- Implementation captures: `/tmp/dao-tab-count-home.png`, `/tmp/dao-tab-count-search.png`, and `/tmp/dao-tab-count-browser.png`.
- Full-view comparison: `/tmp/dao-tab-count-comparison.png`.
- Focused comparison: `/tmp/dao-tab-count-focused-comparison.png`; left shows the reported oversized search-state control, center shows the count removed from expanded search, and right shows the compact browsing-state frame.
- Viewport: Pixel 6 API 34 emulator, 1080 × 2400 physical pixels. The 848 × 1788 framed source was cropped to its 761 × 1687 app screen; the implementation was normalized to 761 × 1687 for the full-view comparison. Native Compose density was preserved in the runtime captures.
- State: light theme, expanded search with `http://www.google.cn/m`; idle new tab; browsing the submitted URL.
- 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.

### Findings and comparison history
**Findings**

- P1 fixed: the tab-count control no longer appears in expanded search, leaving only clear and exit actions.
- P2 fixed: the visible frame no longer fills its 32/36 dp touch target. It is a centered 24 dp rounded square with a 2 dp foreground border, while the larger accessible hit area remains intact.
- Post-fix evidence: the focused comparison shows no count between the two search actions and a compact framed count in the browsing address bar. No actionable P0/P1/P2 differences remain.
- [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.

### Required fidelity surfaces
**Implementation checklist**

- Fonts and typography: the existing system font, semibold weight, and centered numeric label remain consistent; the number was reduced to 11 sp to fit the tighter frame without crowding.
- Spacing and layout rhythm: the visible frame is close to the numeral while the original touch-target spacing is preserved; removing the search-state frame and divider gives the editing actions an even rhythm.
- Colors and visual tokens: the frame and numeral use the existing Nova foreground token for Chrome-like contrast in both themes.
- Image quality and asset fidelity: no raster or icon assets were added or replaced; the control remains native Compose UI.
- Copy and content: no user-visible strings changed, and the live `BrowserStore` count remains the displayed value outside expanded search.
- [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.

final result: passed
**Comparison history**

## Search cursor alignment and empty close behavior — 2026-08-04
- 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.

- Source visual truth: `/var/folders/0l/4dc990md3yn_g3b46dtmhp880000gn/T/orca-paste-1785825111072-1e131078-c517-42cf-811f-4f06c420b9da.png`.
- Implementation screenshot: `/tmp/dao-search-cursor-final.png`.
- Side-by-side comparison: `/tmp/dao-search-reference-vs-final.png`; source is on the left and the revised emulator capture is on the right.
- Viewport: Pixel 6 API 34 emulator at 1080 × 2400 physical pixels and 420 dpi. The 940 × 220 implementation crop was normalized to the 744 × 174 source pixels for comparison.
- State: light theme, empty expanded search, focused real input, visible cursor and clear action.
- Full-view evidence: `/tmp/dao-search-alignment-after.png` confirms the expanded search layout, suggestions region, keyboard, and safe-area placement.
- Focused evidence: `/tmp/dao-search-reference-vs-final.png` confirms the cursor and placeholder share the same centered 16 sp text metrics. A focused region was required because the reported defect was not legible at full-view scale.
**Follow-up polish**

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

- P2 fixed: the placeholder and editable text previously used separate unconstrained decoration children, which made the focused cursor appear vertically disconnected from the placeholder. Both now share one center-start container and the same 16 sp font size and line height.
- P1 fixed: the clear action previously remained a no-op when the expanded query was already empty. It now exits expanded search and restores the homepage; address editing still uses its supplied exit callback.
- First iteration: a shared 20 sp line height aligned the layout structure but made the cursor visibly taller than the reference.
- Final iteration: reducing the shared line height to 16 sp matched the visible cursor/text height while keeping their baseline and origin unified. No actionable P0/P1/P2 differences remain.

### Required fidelity surfaces

- Fonts and typography: system font, 16 sp size, 16 sp line height, weight, and placeholder color are shared between the editable text and placeholder.
- Spacing and layout rhythm: search icon, text origin, clear action, 56 dp pill height, border, and outer padding remain unchanged; only the internal text layout was unified.
- Colors and visual tokens: foreground, faint placeholder, border, and surface continue using the existing Nova theme tokens.
- Image quality and asset fidelity: no image or icon assets changed; the existing Lucide search and close icons remain intact.
- Copy and content: localized placeholder and accessibility labels are unchanged.
- Primary interactions: text entry, non-empty clear, empty close-to-home, keyboard focus, and homepage tab-count restoration were exercised on the emulator.
- Runtime errors: no app fatal exception was observed during the capture and interaction pass.

final result: passed
final result: blocked
2 changes: 1 addition & 1 deletion docs/feature-checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ Flagship feature. C++ services + `dao://dao-agent` WebUI + vendor runtime.
| ☐ | Agent web tools search/fetch tiering | `src/dao/.../resources/agent/web_search/`, `dao_settings_view.ts`, `dao_agent_ui.cc` | — | Provider built-in search is preferred; Auto mode uses configured Jina Search before DuckDuckGo HTML; DuckDuckGo anomaly/verification pages report that accurately instead of `HTML structure changed`; `fetch_url` still falls back from Jina Reader to browser fetch |
| ☐ | Dream scheduler and Agent settings controls | `src/dao/.../agent/dao_dream_service.*`, `dao_settings_view.ts`, `dream_bridge.ts` | — | Dream remains off by default; enabling requires memory; nightly/catch-up/manual runs honor idle/time/date gates and show status/history in settings |
| ☐ | Dream material privacy and excluded-domain filtering | `src/dao/.../agent/dao_dream_material_collector.*`, `dao_dream_domain_utils.*`, `dao_pref_names.*` | — | Excluded domains are normalized and removed before titles/search queries/debug material leave C++; stats do not leak excluded domain names |
| ☐ | Dream report page, rerun, sharing, and habit feedback | `dao_dream_app.ts`, `dao_dream_runner.ts`, `dao_share_image.ts`, `dao_agent_ui.cc` | — | `dao://dream` loads today/history; rerun by date replaces only on success; failed rerun preserves existing report; share image, debug view, confirm/reject habit actions work |
| ☐ | Dream one-minute recap, history, rerun, sharing, and habit feedback | `dao_dream_app.ts`, `dao_dream_runner.ts`, `dao_dream_service.cc`, `dao_share_image.ts`, `dao_agent_ui.cc` | — | `dao://dream` loads up to 371 daily reports for the 53-week activity heatmap plus 53 weekly reports for the shared 14-item history rail; structured summaries, measured per-period foreground rhythm (with legacy model-estimate fallback), uncapped aggregate counts, themes, stats, and memory candidates render; candidates affect memory only after confirmation and rejection preserves existing memory; legacy markdown-only reports derive useful recap content; daily/weekly selection, rerun replacement/failure preservation, share image, full-report disclosure, domain exclusion, debug view, and feedback actions work |

## 4. Picture-in-Picture Enhancements

Expand Down
27 changes: 20 additions & 7 deletions docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,15 +195,28 @@ The stack includes: **LLM tool calling**, **long-term memory** (SQLite + FTS5),
- **DreamMaterialCollector** — aggregates one day of signals: history
(domain+title+time-bucket granularity, top 50; full URLs never leave
the browser), search keywords (extracted in C++), agent conversation
excerpts, proactive-feedback stats.
excerpts, proactive-feedback stats. Visit-count buckets remain available to
the model, while measured foreground seconds are also aggregated by morning,
afternoon, evening, and night for the report rhythm visualization.
- **dao_dream_runner.ts** — resident agent WebUI executes the LLM
summarization (user's configured provider) and returns structured
habits + a morning-report markdown.
- Results: habits merged into `preferences` (LLM confidence capped at
0.8; user confirmation raises to 0.95), report archived in the
`dream_reports` table, morning report card in the Agent panel with
per-habit confirm/reject and an optional debug view of the exact LLM
input (`dao.dream_debug`).
one-minute recap data (summary, time-of-day rhythm, and up to three themes),
habits, and a full morning-report markdown. The recap is persisted inside
the report's existing material-stats JSON, so older databases need no
migration.
- Results: memory suggestions remain report-local candidates until the user
confirms one at confidence 0.95; rejection never deletes or rewrites an
existing preference. The report is archived in the `dream_reports` table,
with a morning report card in the Agent panel, per-candidate confirm/reject,
and an optional debug view of the exact LLM input (`dao.dream_debug`).
- **`dao://dream` one-minute recap** — responsive two-column report with a
53-week real-report activity heatmap, compact daily-and-weekly history rail,
summary card,
measured foreground-focus rhythm, topic cards, aggregate counts,
memory-candidate actions, and a folded full report. Existing rerun, image
sharing, source-domain exclusion,
and debug controls remain available. Legacy markdown-only reports derive a
summary and topic cards locally instead of rendering an incomplete page.

## 3. Picture-in-Picture Enhancements

Expand Down
17 changes: 17 additions & 0 deletions src/dao/browser/agent/dao_agent_memory_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,23 @@ void DaoAgentMemoryService::LoadConversationMessagesInRange(
std::move(callback));
}

void DaoAgentMemoryService::CountUserConversationSessionsInRange(
base::Time start,
base::Time end,
base::OnceCallback<void(int)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
background_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(
[](DaoAgentMemoryStore* store, base::Time start_time,
base::Time end_time) {
return store->CountUserConversationSessionsInRange(start_time,
end_time);
},
store_.get(), start, end),
std::move(callback));
}

// --- Conversation Summaries ---

void DaoAgentMemoryService::SaveConversationSummary(
Expand Down
4 changes: 4 additions & 0 deletions src/dao/browser/agent/dao_agent_memory_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ class DaoAgentMemoryService : public KeyedService {
base::Time end,
int limit,
base::OnceCallback<void(std::vector<ConversationMessage>)> callback);
void CountUserConversationSessionsInRange(
base::Time start,
base::Time end,
base::OnceCallback<void(int)> callback);

// Conversation summaries
void SaveConversationSummary(
Expand Down
15 changes: 14 additions & 1 deletion src/dao/browser/agent/dao_agent_memory_store.cc
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,19 @@ std::vector<ConversationMessage> DaoAgentMemoryStore::LoadRecentMessages(
return result;
}

int DaoAgentMemoryStore::CountUserConversationSessionsInRange(
base::Time start,
base::Time end) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
sql::Statement stmt(db_->GetCachedStatement(
SQL_FROM_HERE,
"SELECT COUNT(DISTINCT session_id) FROM conversations "
"WHERE role='user' AND timestamp>=? AND timestamp<?"));
stmt.BindInt64(0, TimeToInt(start));
stmt.BindInt64(1, TimeToInt(end));
return stmt.Step() ? stmt.ColumnInt(0) : 0;
}

std::vector<ConversationMessage>
DaoAgentMemoryStore::LoadConversationMessagesInRange(base::Time start,
base::Time end,
Expand Down Expand Up @@ -1708,7 +1721,7 @@ std::optional<DreamReport> DaoAgentMemoryStore::GetDreamReportByDate(

std::vector<DreamReport> DaoAgentMemoryStore::GetDreamReports(int limit) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
limit = std::clamp(limit, 1, 100);
limit = std::clamp(limit, 1, 371);
sql::Statement stmt(db_->GetUniqueStatement(
base::StrCat({"SELECT ", kDreamReportColumns,
" FROM dream_reports WHERE status = 'completed' "
Expand Down
1 change: 1 addition & 0 deletions src/dao/browser/agent/dao_agent_memory_store.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class DaoAgentMemoryStore {
base::Time start,
base::Time end,
int limit);
int CountUserConversationSessionsInRange(base::Time start, base::Time end);

// Conversation summaries
bool SaveConversationSummary(const ConversationSummary& summary);
Expand Down
Loading
Loading