Verify + extend DOM-SETTINGS/SEARCH/NOTIFICATIONS (2026-10-04, 3 nodes)
Session: sidechat/dom-settings
This commit is contained in:
+63
-13
@@ -1,23 +1,30 @@
|
||||
# DOM reference: notifications & activity (muse.ai)
|
||||
|
||||
Inspected live via CDP on the opm browser (warp-opm netns, port 9440),
|
||||
2026-10-04. Companion docs: `DOM-CHAT-PANEL.md`, `DOM-MESSAGES.md`,
|
||||
2026-10-04. Re-verified 2026-10-04 across all three fleet nodes
|
||||
(muse 9410, pip 9420, opm 9440).
|
||||
Companion docs: `DOM-CHAT-PANEL.md`, `DOM-MESSAGES.md`,
|
||||
`DOM-PAGE-STRUCTURE.md`.
|
||||
|
||||
## TL;DR
|
||||
|
||||
muse.ai has **no bell icon and no notification center/dropdown**. The
|
||||
notification surface is three separate things:
|
||||
notification surface is four separate things:
|
||||
|
||||
1. **Toast live region** — `section[aria-label="Notifications alt+T"]`
|
||||
(transient toasts, aria-live).
|
||||
2. **Activity tab** — `button[aria-label="Activity"]` in the status-panel
|
||||
toolbar (activity feed; tabs: Activity / Approvals / Upcoming / Identity).
|
||||
3. **Chat nav unread** — `a[data-testid="hatch-nav-chat"]` whose `aria-label`
|
||||
becomes `"Chat, N notification(s)"` when chats are unread.
|
||||
becomes `"Chat, N notification(s)"` when chats are unread (observed live on
|
||||
pip: `"Chat, 1 notification"`, later cleared to `"Chat"`).
|
||||
4. **Unread dot badges** — transient blue-dot `SPAN`s (see §5). **Correction
|
||||
2026-10-04:** these DO exist; the earlier "no badge elements" claim was
|
||||
wrong — the first sweep ran on opm while it was clean, and the badges only
|
||||
render while there is unread activity.
|
||||
|
||||
There are no badge/dot/pill unread elements in the DOM, and no element with
|
||||
`notif` in its `data-testid`.
|
||||
There is no bell icon. The one `data-testid` containing `notif` is
|
||||
`hatch-dock-chat-notification-badge` (see §5).
|
||||
|
||||
---
|
||||
|
||||
@@ -191,20 +198,55 @@ Do not match the element itself by aria-label — the count suffix changes.
|
||||
|
||||
## 5. What does NOT exist
|
||||
|
||||
Verified absent (three DOM sweeps, 2026-10-04):
|
||||
Verified absent (sweeps on all three nodes, 2026-10-04):
|
||||
|
||||
- No bell icon element.
|
||||
- No `data-testid` containing `notif` (full inventory checked).
|
||||
- No badge / dot / pill / count / unread elements anywhere in the DOM
|
||||
(regex sweep over testids, class names, and aria-labels — zero hits).
|
||||
- No bell icon element (zero `aria-label` matches for /bell/i on every node).
|
||||
- No notification dropdown, menu, or dialog container.
|
||||
- No `[data-radix-portal]` / portal roots hosting hidden dropdowns.
|
||||
- Clicking the Activity tab revealed no additional notification list UI
|
||||
(the status panel was already open on the Activity feed).
|
||||
|
||||
Unread state is therefore conveyed **only** through:
|
||||
1. the `hatch-nav-chat` aria-label suffix, and
|
||||
2. (presumably) unread styling on individual `[data-testid="hatch-thread-row"]`
|
||||
## 5a. Unread dot badges — CORRECTION 2026-10-04
|
||||
|
||||
The earlier claim ("no badge / dot / pill elements anywhere") is **wrong**.
|
||||
Three badge testids exist; they render only while there is unread activity and
|
||||
are absent when clean (which is why the first sweep on opm missed them):
|
||||
|
||||
| `data-testid` | Observed on | Markup |
|
||||
|---|---|---|
|
||||
| `hatch-dock-chat-notification-badge` | pip (while `"Chat, 1 notification"`) | blue dot |
|
||||
| `hatch-chat-switcher-unread-indicator` | muse | `<span class="bg-fill-blue absolute -end-0.5 size-2 rounded-full">` — 8×8 blue dot, no text, no `aria-label` |
|
||||
| `hatch-invite-activity-badge` | muse, pip | `<span class="bg-fill-blue absolute -end-0.5 -top-0.5 size-2 rounded-full">` — 8×8 blue dot |
|
||||
|
||||
All are empty `SPAN`s (`innerText === ""`, no `aria-label`, no `role`) —
|
||||
pure CSS dots (`bg-fill-blue`, `rounded-full`, `size-2`). **They are transient**:
|
||||
pip's `hatch-dock-chat-notification-badge` was present during one sweep and gone
|
||||
minutes later after the unread cleared. Never match on class names (Tailwind);
|
||||
match on `data-testid` presence:
|
||||
|
||||
```js
|
||||
// Any unread-dot badges currently rendered?
|
||||
const unreadDots = [
|
||||
'hatch-dock-chat-notification-badge',
|
||||
'hatch-chat-switcher-unread-indicator',
|
||||
'hatch-invite-activity-badge',
|
||||
].filter(tid => document.querySelector(`[data-testid="${tid}"]`));
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- `hatch-invite-activity-badge` was present on muse and pip even when the chat
|
||||
nav label was clean (`"Chat"`), so it likely signals invites/activity rather
|
||||
than chat unread — treat it as its own signal, not as "unread chats".
|
||||
- `hatch-chat-switcher-unread-indicator` sits on the chat switcher (rect ≈
|
||||
(110,20), 8×8 on muse) — useful when the panel is open and the nav label
|
||||
is out of view.
|
||||
|
||||
Unread state is therefore conveyed through:
|
||||
|
||||
1. the `hatch-nav-chat` aria-label suffix (`"Chat, N notification(s)"`),
|
||||
2. the transient dot badges above (`data-testid` presence),
|
||||
3. (presumably) unread styling on individual `[data-testid="hatch-thread-row"]`
|
||||
rows in the chat panel — see `DOM-CHAT-PANEL.md`. The panel was closed
|
||||
during this inspection so row-level unread markers were not sampled;
|
||||
re-probe with the panel open if row-level detection is needed.
|
||||
@@ -222,6 +264,12 @@ document.querySelector('section[aria-label="Notifications alt+T"]')
|
||||
/notification/.test(
|
||||
document.querySelector('[data-testid="hatch-nav-chat"]').getAttribute('aria-label'));
|
||||
|
||||
// Any unread dots currently rendered? (transient — absent when clean)
|
||||
['hatch-dock-chat-notification-badge',
|
||||
'hatch-chat-switcher-unread-indicator',
|
||||
'hatch-invite-activity-badge'
|
||||
].filter(tid => document.querySelector(`[data-testid="${tid}"]`));
|
||||
|
||||
// Open the Activity feed (select tab):
|
||||
document.querySelector('button[aria-label="Activity"]').click();
|
||||
// Which status tab is selected?
|
||||
@@ -240,3 +288,5 @@ document.querySelector('button[data-testid="hatch-status-panel-close"]').click()
|
||||
- Whether tab buttons ever carry counts/badges when items are pending
|
||||
(Approvals tab is the likely candidate — re-probe with a pending approval).
|
||||
- Row-level unread markers inside `hatch-thread-row` (needs panel-open probe).
|
||||
- What clears `hatch-dock-chat-notification-badge` vs the aria-label suffix
|
||||
(observed independently transient on pip/muse — may be separate signals).
|
||||
|
||||
+36
-5
@@ -3,6 +3,7 @@
|
||||
Muse.ai global search (quick-search / command palette). Inspected live on bl via CDP
|
||||
against the opm browser (warp-opm netns, CDP 127.0.0.1:9440) on 2026-10-04.
|
||||
All selectors verified against the live DOM.
|
||||
Re-verified end-to-end 2026-10-04 (open → type → results → empty state → Escape).
|
||||
|
||||
Related: `docs/DOM-CHAT-PANEL.md` (chat panel), `docs/DOM-MESSAGES.md`,
|
||||
`docs/DOM-PAGE-STRUCTURE.md`.
|
||||
@@ -153,14 +154,40 @@ document.querySelectorAll('[data-testid="hatch-quick-search-frame"] [data-testid
|
||||
|---|---|---|
|
||||
| `chat:main` | Main chat | `chat:main` |
|
||||
| `chat:thread:<uuid>` | Sidechat thread — **the thread UUID is embedded** | `chat:thread:2e2c90a1-4b17-4590-b8ba-fb17d8018d36` |
|
||||
| `chat:message:<msg-id>:<n>` | Individual message match inside a thread | `chat:message:assistant-msg-b2a4e27d-4970-8b1e-8863-a96ed0aa1401:20420` |
|
||||
| `chat:message:assistant-msg-<uuid>:<n>` | Individual assistant message match inside a thread | `chat:message:assistant-msg-b2a4e27d-4970-8b1e-8863-a96ed0aa1401:20420` |
|
||||
| `chat:message:<uuid>:<n>` | Individual message match (non-assistant id form) | `chat:message:08a44cdd-91a7-408e-9073-743e7e15d50f:20890` |
|
||||
|
||||
Search matches **both threads and individual messages**. A query like `"heartbeat"`
|
||||
returned 12 results mixing `chat:thread:*` and `chat:message:*` values.
|
||||
returned 12 results on 2026-10-04 re-verify: 6 `chat:thread:*` + 6 `chat:message:*`,
|
||||
mixing both message id forms.
|
||||
|
||||
This is a ready-made thread-lookup mechanism: search for a sidechat name, read
|
||||
`data-value`, extract the UUID — no title-matching or URL polling needed.
|
||||
|
||||
### Full result-item markup (verified 2026-10-04)
|
||||
|
||||
```html
|
||||
<div data-slot="command-item"
|
||||
data-testid="command-palette-item"
|
||||
id="radix-_r_1e9_" <!-- random per item per render — do not match -->
|
||||
cmdk-item=""
|
||||
role="option"
|
||||
aria-disabled="false" aria-selected="true"
|
||||
data-disabled="false" data-selected="true"
|
||||
data-value="chat:thread:778fbbfa-3bf8-4163-bfe6-92c0f88657e8"
|
||||
class="... h-12 items-center gap-2 p-1.5 ...">
|
||||
<span class="bg-fill-secondary flex size-9 ...rounded-full">…svg icon…</span>
|
||||
<span class="flex min-w-0">…title + snippet + relative time…</span>
|
||||
</div>
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- The **first result is auto-highlighted** on render (`aria-selected="true"` /
|
||||
`data-selected="true"`); the input's `aria-activedescendant` points at it.
|
||||
Enter would activate it (navigation not tested).
|
||||
- `data-value` is the stable automation hook; `id` is random per render.
|
||||
|
||||
---
|
||||
|
||||
## 5. Groups
|
||||
@@ -247,9 +274,13 @@ Detection: `querySelector('[cmdk-empty]')` non-null, or item count `=== 0`.
|
||||
// CDP: Input.dispatchMouseEvent mousePressed + mouseReleased at (r.x + r.width/2, r.y + r.height/2)
|
||||
```
|
||||
JS `.click()` on the trigger is unreliable (Radix wants trusted events).
|
||||
2. **Never JS-touch the input.** `focus()`, `click()`, or the native value setter
|
||||
on `command-palette-search-input` closes the dialog. The input auto-focuses on
|
||||
open — just send trusted key events (`rawKeyDown` → `char` → `keyUp`).
|
||||
2. **Type with CDP `Input.insertText`** (verified 2026-10-04 — simplest reliable
|
||||
path). The raw `rawKeyDown` → `char` → `keyUp` sequence also works but is
|
||||
unnecessary. **Never JS-touch the input** (`focus()`, `click()`, native value
|
||||
setter): synthetic interaction on the input **closes the dialog** (verified
|
||||
twice). One exception observed once: `input.select()` on the already-open
|
||||
dialog did *not* close it — usable for clearing, but Escape-and-reopen
|
||||
remains the safest clear.
|
||||
3. **Closed === absent.** After Escape the dialog node is gone; check
|
||||
`querySelector(...) === null`, with optional chaining (`?.offsetParent`) —
|
||||
without `?.` a missing node throws and a truthy error string can false-positive
|
||||
|
||||
+65
-36
@@ -1,6 +1,7 @@
|
||||
# DOM Reference: Settings, Profile & Dock Rail
|
||||
|
||||
Inspected live via CDP on the opm browser (warp-opm netns, CDP 9440), 2026-10-04.
|
||||
Re-verified 2026-10-04 across all three fleet nodes (muse 9410, pip 9420, opm 9440).
|
||||
Structure only — no credential, token, or personal values are recorded here.
|
||||
|
||||
Related: `DOM-CHAT-PANEL.md` (chat panel), `DOM-MESSAGES.md` (messages),
|
||||
@@ -18,12 +19,24 @@ The left vertical nav rail. Container:
|
||||
|
||||
### Rail items (top to bottom)
|
||||
|
||||
| # | Selector | Tag | `aria-label` | Notes |
|
||||
|---|----------|-----|--------------|-------|
|
||||
| 1 | `[data-testid="hatch-nav-chat"]` | `<a href="/">` | `Chat` | The chat/message button from the user's screenshot. Navigates `/thread/new` → `https://muse.ai/`. See "chat activation" below. |
|
||||
| 2 | `[data-testid="hatch-nav-search"]` | `<button>` | `Search` | Opens quick-search dialog `[data-testid="hatch-quick-search-frame"]` (heading "Search Muse"). |
|
||||
| 3 | *(none)* | `<button>` | `Get the Muse app` | App download upsell. No `data-testid`. |
|
||||
| 4 | `[data-testid="hatch-dock-more"]` | `<button>` | `Settings` | Opens the settings menu (radix menu). Bottom of rail (`div.mt-auto`). |
|
||||
| # | Selector | Tag | `aria-label` | `data-pel-click` | Notes |
|
||||
|---|----------|-----|--------------|------------------|-------|
|
||||
| 1 | `[data-testid="hatch-nav-chat"]` | `<a href="/">` | `Chat` (unstable — see notifications doc) | `chat_tab_click` | The chat/message button from the user's screenshot. Navigates `/thread/new` → `https://muse.ai/`. See "chat activation" below. |
|
||||
| 2 | `[data-testid="hatch-nav-search"]` | `<button>` | `Search` | `quick_search_nav_click` | Opens quick-search dialog `[data-testid="hatch-quick-search-frame"]` (heading "Search Muse"). |
|
||||
| 3 | *(none)* | `<button>` | `Get the Muse app` | `mobile_app_upsell_click` | App download upsell. No `data-testid`. |
|
||||
| 4 | `[data-testid="hatch-dock-more"]` | `<button>` | `Settings` | `settings_menu_open_click` | Opens the settings menu (radix menu). Bottom of rail (`div.mt-auto`). |
|
||||
|
||||
Mid-rail system items (verified 2026-10-04, all three nodes) — `DIV`s, not
|
||||
buttons, between the search button and the app upsell:
|
||||
|
||||
| `data-testid` | `aria-label` |
|
||||
|---|---|
|
||||
| `hatch-nav-system-item-66656564` | `Feed` |
|
||||
| `hatch-nav-system-item-6964656173` | `Ideas` |
|
||||
| `hatch-nav-system-item-676f616c73` | `Goals` |
|
||||
| `hatch-nav-system-item-6c696272617279` | `Library` |
|
||||
|
||||
(The hex suffixes decode to ascii: `feed`, `ideas`, `goals`, `library`.)
|
||||
|
||||
Parent chain of the settings button (4 levels):
|
||||
|
||||
@@ -41,14 +54,16 @@ Key attributes on the button:
|
||||
aria-label="Settings"
|
||||
data-testid="hatch-dock-more"
|
||||
aria-haspopup="menu"
|
||||
aria-expanded="false" <!-- unreliable: stays "false" even when menu is open -->
|
||||
aria-expanded="false" <!-- RELIABLE after 2026-10-04 re-verify: "true" when menu open -->
|
||||
data-state="closed" <!-- unreliable: stays "closed" even when menu is open -->
|
||||
data-pel-click="settings_menu_open_click">
|
||||
```
|
||||
|
||||
> **Automation note:** `data-state` / `aria-expanded` do NOT reflect the real
|
||||
> open state. Detect the open menu by counting `[role="menuitem"]` elements
|
||||
> (`> 0` means open). Synthetic `.click()` does not open the radix menu;
|
||||
> **Automation note (updated 2026-10-04):** `data-state` does NOT reflect the
|
||||
> real open state (stays `"closed"`). `aria-expanded`, however, **does**:
|
||||
> verified `"true"` on opm with the menu open (earlier claim that it stays
|
||||
> `"false"` was wrong — possibly a timing artifact). Belt and braces: detect
|
||||
> the open menu by counting `[role="menuitem"]` elements (`> 0` means open). Synthetic `.click()` does not open the radix menu;
|
||||
> use real mouse events via CDP `Input.dispatchMouseEvent`
|
||||
> (`mousePressed` + `mouseReleased` at the button center). The button toggles,
|
||||
> so click only when `[role="menuitem"]` count is 0.
|
||||
@@ -66,11 +81,12 @@ always match on the `data-testid`.
|
||||
|
||||
## 2. Settings menu (dock "more" menu)
|
||||
|
||||
Radix menu rendered in a popper. Items (`role="menuitem"`, no `data-testid`):
|
||||
Radix menu rendered in a popper. Items are **`DIV`s with `role="menuitem"`**
|
||||
(verified 2026-10-04 — not buttons), no `data-testid`:
|
||||
|
||||
| Text | `data-pel-click` | Action (observed) |
|
||||
|------|------------------|-------------------|
|
||||
| Keyboard shortcuts | `keyboard_shortcuts_nav_click` | No dialog rendered under automation (see §5) |
|
||||
| Keyboard shortcuts | `keyboard_shortcuts_nav_click` | No dialog under automation (see §5) |
|
||||
| Download apps | `mobile_app_upsell_menu_click` | — (not opened) |
|
||||
| Report an issue | `bug_report_nav_click` | — (not opened) |
|
||||
| Settings | `settings_nav_click` | Opens the Settings dialog (§3) |
|
||||
@@ -124,38 +140,49 @@ Close
|
||||
|
||||
### 3b. General section
|
||||
|
||||
Headings (all `h2`): `General`, `Usage`, `Appearance`.
|
||||
Headings (all `h2`, in order): `General`, `Meta Account`, `Usage`, `Appearance`.
|
||||
|
||||
**Usage** — one button:
|
||||
**Meta Account** — row labeled `Password, security, personal details`
|
||||
(structure only; not opened).
|
||||
|
||||
| Control | Label | Notes |
|
||||
|---------|-------|-------|
|
||||
| `<button>` | `Upgrade` | Plan upgrade upsell |
|
||||
**Usage** — plan and quota rows (structure only, values not recorded):
|
||||
|
||||
| Row | Notes |
|
||||
|-----|-------|
|
||||
| Plan name + weekly reset line | e.g. plan tier + "Weekly limit resets on <date>" |
|
||||
| Usage bar(s) with percentage | at least two bars observed (weekly + additional) |
|
||||
| `Upgrade` button | `data-pel-click="settings_general_upgrade_click"` |
|
||||
| `Language` | control follows the usage block |
|
||||
|
||||
**Appearance** — theme + accent color:
|
||||
|
||||
| Control | Label |
|
||||
|---------|-------|
|
||||
| `<button>` | `Light` |
|
||||
| `<button>` | `Dark` |
|
||||
| `<button>` | `System` |
|
||||
| `<input type="radio">` | `Match my avatar` |
|
||||
| `<input type="radio">` | `Default` |
|
||||
| `<input type="radio">` | `Blue` |
|
||||
| `<input type="radio">` | `Purple` |
|
||||
| `<input type="radio">` | `Pink` |
|
||||
| `<input type="radio">` | `Orange` |
|
||||
| `<input type="radio">` | `Green` |
|
||||
| `<input type="radio">` | `Beige` |
|
||||
| `<input type="radio">` | `Monochrome` |
|
||||
| Control | Label source | Selection state |
|
||||
|---------|--------------|-----------------|
|
||||
| `<button aria-label="Light">` | `aria-label` (icon-only, no text) | `aria-pressed` |
|
||||
| `<button aria-label="Dark">` | `aria-label` | `aria-pressed` |
|
||||
| `<button aria-label="System">` | `aria-label` | `aria-pressed="true"` on opm (verified) |
|
||||
| 9× `<input type="radio">` | **`aria-label`**, not innerText | `checked` |
|
||||
|
||||
Radio `aria-label`s in order: `Match my avatar` (checked on opm), `Default`,
|
||||
`Blue`, `Purple`, `Pink`, `Orange`, `Green`, `Beige`, `Monochrome`.
|
||||
All share one radio group (`name` is random per render, e.g. `_r_184_`).
|
||||
|
||||
### 3c. Profile / avatar
|
||||
|
||||
- Avatar image: `<img>` with empty `alt`, `src` present (value not recorded).
|
||||
No `data-testid` on the img.
|
||||
- `Edit avatar and name` button (`aria-label="Edit avatar and name"`,
|
||||
`<button>`, no `data-testid`) appears in the profile area of the settings
|
||||
dialog. Chain (3 levels):
|
||||
`<button>`, no `data-testid`, id is a random `radix-_R_…` value).
|
||||
|
||||
> **Correction 2026-10-04:** the button is **not a descendant of
|
||||
> `div[role="dialog"]`**. While the settings dialog is open it renders as a
|
||||
> sibling overlay inside `[data-testid="hatch-status-panel-sliding-surface"]`
|
||||
> (nearest testid ancestor at depth 10; button rect ≈ (622,141), 32×32 on a
|
||||
> 780px-wide viewport). It appears only while the dialog is open and is gone
|
||||
> after Escape. **Match it by `aria-label`, never by dialog containment.**
|
||||
> The 3-level parent chain below is still accurate:
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
div.pointer-events-auto.absolute.z-20
|
||||
@@ -195,9 +222,11 @@ Menu item exists:
|
||||
|
||||
Clicking it via automation (menuitem `.click()` after opening the dock menu
|
||||
with real mouse events) produced **no `[role="dialog"]`** within 3s and no
|
||||
URL change. The modal likely requires a trusted user gesture deeper in the
|
||||
radix event chain, or renders on a longer delay. **Status: selector documented,
|
||||
modal content not captured** — needs a headed/manual pass or longer wait.
|
||||
URL change. Re-tested 2026-10-04 with **real mouse events**
|
||||
(`Input.dispatchMouseEvent` press+release on the menuitem): still no dialog
|
||||
within 3s; the menu simply closes. The menuitem carries no kbd hint in its
|
||||
markup (icon SVG + text "Keyboard shortcuts" only).
|
||||
**Status: selector documented, modal content not captured** — needs a headed/manual pass.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user