Conversation
The swinging bell was a second, worse indicator for a fact the alarm wash
and perimeter ring already carry, and its tilt tiers were status trivia.
Every surface now shows a ring the same way:
- Pane header: no bell and no tint — the Pane overlay outlines it. The
header's right-click and command-mode `a` remain the context's entry
points.
- Door: the inset ring alone; the SPOKEN speaker glyph now sits beside the
TODO pill rather than beside a bell.
- Hidden Workspace tab: a 2px inset in `alarm-vs-header-inactive`, its
arrival burst keyed on the union's earliest-started ringing member's
episode, so a later member or a Workspace switch cannot replay it.
`WorkspaceRingCues` and its per-Workspace generation are gone.
- Mobile: the ringing session-list row and the header bar wear the inset,
and a plain `Dismiss alert` button appears while ringing — the mobile
composition has no terminal context to reach.
The bell's `--animate-bell-ring` keyframes go with it; its four-cycle
measurements move to the alarm pulse's rationale, which they now back.
The vscode-ext guide loses its four bell GIFs for two sentences about the
outlined pane, and the playground tutorial loses `al-busy` ("the bell tilts
while the command works"), which had nothing left to show.
`AlertState.ringSeq` survives unread for now: the manager still counts
latches and `alertStatesEqual` still compares it. Remaining readers are
`MobileWall.tsx`, `MobileTerminalSessionItem`, and `wall-model.ts`.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Follow-up cleanups on the bell retirement, all behavior-preserving except the mobile dismissal: - `AlertRingInset` in `alert-ring.tsx` (the module gains JSX, so `.ts` -> `.tsx`) renders the keyed overlay the Door, the Workspace tab, the mobile row and the mobile header each hand-assembled. The 2px shadow literals live in one `Record<AlertRingGround, string>` in `design.tsx`, replacing `DOOR_ALARM_INSET_CLASS` / `WORKSPACE_TAB_ALARM_INSET_CLASS`; the caller passes only its own corner radius. `data-alert-ring-inset` now carries the ground, which is what the tests assert. - Mobile rows and the mobile header carry `episode` in place of the unread `ringSeq`, and derive their row through `alertRingRow` + `useAlertRingBurst` like every other surface instead of testing `status` by hand. A remote row passes `episode: null`: `DirectoryEntry.ringing` is edgeless, so there is no start to clock a burst from. - The mobile "Dismiss alert" button is gone. A tap on the terminal attends the Session, which is what puts the ring out — the same verb desktop uses, and keystrokes already attended. Pocket is unchanged either way, its `alertAttend` being inert; `remote-api.md` -> Future now names the missing `terminal.attend`. - The Workspace union carries `ringingSince` rather than a borrowed member episode, and the strip holds it for the whole ringing interval, so attending the member that started the ring cannot advance it to a survivor's later start and re-burst the tab. - `HeaderActionButton` loses `tooltipDetail`, `tooltipAlign`, `onMouseDownCapture` and `onContextMenu`, none of which has a caller left; `alertRingBurstProps` and `animationClockStyle` lose their last outside caller with the bell and go module-private. - `Ringing` / `TodoAndRinging` header stories rendered identically to `Default` / `TodoOnly`; the untinted ringing header is pinned in `TerminalPaneHeader.test.tsx` instead. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Deploying mouseterm with
|
| Latest commit: |
f4f760a
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://6459659f.mouseterm.pages.dev |
| Branch Preview URL: | https://alert-retire-bell.mouseterm.pages.dev |
dormouse-bot
left a comment
There was a problem hiding this comment.
Feedback on work in progress, not a merge verdict — mark the PR ready when you want the full pass. Two findings, both with inline suggestions.
The walkthrough's ringing probe reads the wrong element. sessionRowsExpr now tests row.className for alarm-vs, but AlertRingInset paints that token onto an overlay <span> inside the row button; the button itself only ever carries bg-app-bg / bg-header-active-bg plus the focus-ring shadow. ringing is therefore always false, and step 8's waitUntil on r.todo && r.ringing && r.text.includes('777;notify') burns its full 60s and fails — the silent-probe failure the change was meant to prevent, traded for a loud one. The sibling todo probe on the line above already queries descendants; data-alert-ring-inset is the stable hook for this one.
A Workspace that starts ringing while it is visible never bursts its tab. unionFor returns EMPTY_WORKSPACE_UNION for the active Workspace without touching unionsRef, so the cached entry goes on describing whatever that Workspace looked like the last time it was hidden. Sequence: Workspace B is hidden and ringing, so the cache holds ringing: true, ringingSince: T1; the user switches to B and attends it; a member rings again at T2; the user switches away. The carry-forward branch sees previous.ringing && projected.ringing and holds T1, so the burst's animationDelay is -(now - T1) — already past the animation's end — and the tab wears a static edge for a summons that should have flashed. The retired WorkspaceRingCues covered this deliberately ("Cues observe the active Workspace too, so switching tabs cannot create one"); the replacement drops it. Dropping the cache entry while active restores the behavior without reintroducing a switch-replay: a genuinely uninterrupted ring still resolves to its member's original startedAt, so its clock is still expired on return, and the projection stays skipped for the visible tab.
| text: row.innerText.trim(), | ||
| todo: [...row.querySelectorAll('span')].some((el) => el.textContent.trim() === 'TODO'), | ||
| ringing: row.querySelectorAll('svg').length > 1, | ||
| ringing: /alarm-vs/.test(row.className), |
There was a problem hiding this comment.
The alarm token lands on the AlertRingInset overlay span, not on the row button, so this is always false. Match the todo probe above and query the descendant by its data hook.
| ringing: /alarm-vs/.test(row.className), | |
| ringing: row.querySelector('[data-alert-ring-inset]') !== null, |
| @@ -157,12 +153,19 @@ export function WorkspaceStrip({ | |||
| } | |||
| const unionFor = (id: WorkspaceId, active: boolean): WorkspaceUnion => { | |||
| if (active) return EMPTY_WORKSPACE_UNION; | |||
There was a problem hiding this comment.
Returning early without touching unionsRef leaves the active Workspace's cached union describing a ring that may already have ended, which the carry-forward below then holds onto. Dropping the entry keeps the projection skipped for the visible tab and lets the next hidden render start from the truth.
| if (active) return EMPTY_WORKSPACE_UNION; | |
| // A visible Workspace shows no indicators, and its cached union must not | |
| // outlive the ring it described: a ring that ends while the Workspace is | |
| // active would otherwise carry its `ringingSince` into the next one. | |
| if (active) { | |
| unionsRef.current.delete(id); | |
| return EMPTY_WORKSPACE_UNION; | |
| } |
| Changes from today's nine: `al-busy` (the pane's in-progress feedback) | ||
| is **cut** as a step — it is feedback, not a concept, and it is what the user is | ||
| already staring at during Beat 2. `al-ring` is **split into three** so each | ||
| attention mechanism gets its own line. Everything else keeps its id. |
There was a problem hiding this comment.
This PR cuts al-busy, so today's list is eight and the cut is no longer a pending change.
| Changes from today's nine: `al-busy` (the pane's in-progress feedback) | |
| is **cut** as a step — it is feedback, not a concept, and it is what the user is | |
| already staring at during Beat 2. `al-ring` is **split into three** so each | |
| attention mechanism gets its own line. Everything else keeps its id. | |
| Changes from today's eight: `al-ring` is **split into three** so each | |
| attention mechanism gets its own line. Everything else keeps its id. |
Stacked on #709.
The swinging bell was a second, worse indicator for a fact the whole-Pane alarm treatment already shows, and its tilt tiers (
MIGHT_BE_BUSY/BUSY/ … ) were status trivia. It is gone from every surface: pane header, Door, hidden Workspace tab, mobile session list and header. WATCHING state lives in the terminal context and Settings.AlertBell,bell-icon-class,WorkspaceRingCues, thebell-ringkeyframes, the four README GIFs, the tutorial's "bell tilts" step, and the header's alert button (itsHeaderActionButtonprops went with it).<AlertRingInset ground=…>component (fromalert-ring.tsx) draws the 2px alarm edge on the Door, the hidden Workspace tab, and the mobile rows/header, with the shadow literals in one table indesign.tsx.ringingSince(one uninterrupted ringing interval at Workspace scope, carried forward while any member still rings) so the hidden tab bursts once and never re-bursts when the oldest member is attended.remote-api.md→ Future namesterminal.attend.scripts/pairing-walkthrough's ringing probe counted<svg>elements and would have gone silent; it now matches the alarm class.alert.mdPane Header / Door / Workspace union rewritten; the four-cycle bell paragraphs and their rationale deleted, the Chrome-150 measurements folded into the per-episode pulse rationale.alert.md7200 → 7050;mobile-terminal-ui.md1950 → 2000.ringSeqis still published by the manager; the next PR deletes it end to end.🤖 Generated with Claude Code