toga-ai 1.0.587 → 1.0.588

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -123,7 +123,8 @@ poll's:
123
123
  - The **first successful poll is the baseline**, so opening the page mid-outage is **silent**
124
124
  (the standing tint, being level-triggered, still shows immediately).
125
125
  - A state that simply persists never re-alarms.
126
- - A full recovery to operational is **silent** (the monitor drops out of the row set entirely).
126
+ - A full recovery to operational is **visually silent** (no popup, no tint) but now plays a
127
+ distinct **recovery chime** — see the recovery event below.
127
128
  - It fires on **any change of non-operational state** — `r.role !== previous.get(r.key)`, where
128
129
  the row set only ever holds non-operational monitors, so good→degraded, good→offline,
129
130
  degraded→offline **and offline→degraded** all alert. An earlier version compared severity
@@ -134,11 +135,30 @@ poll's:
134
135
  The event presentation, held for `ALERT_HOLD_MS` (5s):
135
136
 
136
137
  - **Sound** — Web Audio beeps, synthesised at runtime, so there is **no audio asset to ship**.
137
- **1 beep @ 720 Hz** degraded, **2 beeps @ 990 Hz** offline. The beep count describes the state
138
- the monitor is in **now**, so an offline → degraded change beeps **once**. Pitch differs too,
139
- so severity is recognisable across a room without counting.
140
- - **Popup** — a centre overlay naming each affected monitor.
138
+ Each role's sound is defined in a single `ALERT_SOUND` table keyed by role, read by a
139
+ generalised `playBeeps(role)` (signature unchanged: role → bool). Each entry carries a beep
140
+ **count**, base **freq** (Hz), a per-beep **step** (Hz added to each successive beep — `0` =
141
+ flat, positive = a rising chime), duration/gap/volume, and a **wave** shape. Current tuned
142
+ values: **warning (degraded) = 3× square @ 720 Hz** (flat), **critical (offline) = 4× square
143
+ @ 410 Hz** (flat), **recovered = 3× square rising chime 620 → 800 → 980 Hz** (freq 620,
144
+ step 180). Distinct count, pitch and the rising vs. flat contour make each event
145
+ recognisable across a room without looking. The three sounds were tuned by ear in a
146
+ throwaway standalone "Monitor Sound Lab" browser page and the final numbers ported in — the
147
+ lab is not part of the repo.
148
+ - **Popup** — a centre overlay naming each affected monitor. **Bad-state events only** —
149
+ recovery fires no popup.
141
150
  - **Blink** — the tint element gains `.is-blinking` for the 5s pulse, then the colour **holds**.
151
+ **Bad-state events only** — recovery fires no blink and no tint.
152
+
153
+ **Recovery event — audio-only, by design.** `useMonitorAlerts` also computes `recovered` = keys
154
+ that were non-operational in the previous poll and have **dropped out of `model.rows`** this poll,
155
+ and calls `playBeeps('recovered')` (the rising chime) for them. It deliberately fires **no popup
156
+ and no screen tint**: the level-triggered standing tint already clears itself when a row leaves
157
+ the set, and a green "all clear" popup/flash would fight the "the board only shouts when something
158
+ is wrong" design. So recovery is silent **visually** but audible. Two edge rules: the **first
159
+ poll is still the baseline** (opening the page mid-outage does not chime), and if a bad-state
160
+ change and a recovery land in the **same 5s poll the bad-state alert wins** that tick, avoiding
161
+ overlapping sounds (simultaneous transitions are rare).
142
162
 
143
163
  **State — `standingRole(model)`** returns `critical` if any row is offline, else `warning` if any
144
164
  is degraded, else `null` (no tint). The tint element only renders while `standingRole` is
@@ -148,8 +168,10 @@ Note the two can legitimately show different colours at once: the tint always re
148
168
  **worst-current** state while the popup reflects **the event**, so a degraded-event popup can sit
149
169
  on a red screen because something else is still offline. That is correct, not a bug.
150
170
 
151
- Verified across full cycles: beep sequence 720 / 990 990 / 720, silent on unchanged and on
152
- recovery, popup held 4982 ms and 4955 ms against the 5s spec; amber standing → red when offline
171
+ Verified across full cycles (against the original 1-beep-720 / 2-beep-990 tuning; the current
172
+ values are 3×720 / 4×410 / recovered 620→800→980): distinct sounds per event, silent on
173
+ unchanged, recovery now chimes but stays visually silent, popup held 4982 ms and 4955 ms against
174
+ the 5s spec; amber standing → red when offline
153
175
  joined (priority) → amber when offline cleared → no tint on full recovery, with the blink
154
176
  stopping after 5s and the colour held. Circle verified against the DOM: `#0ca30c` all-clear,
155
177
  `#fab219` degraded only, `#d03b3b` with 1 degraded + 1 offline, and `textNodesInSvg = 0`.
@@ -209,8 +231,9 @@ reduced-motion viewer never lands on a fully-invisible (opacity 0) glow.
209
231
  OneUptime call returns HTTP 200 with a malformed or empty body, `buildMonitorModel` yields
210
232
  total 0, empty buckets and empty rows. The status pill correctly degrades to "Unknown", but
211
233
  the affected-list card still reads **"All 0 monitors are operational"**, and any
212
- previously-degraded monitor silently disappears **with no alert** (recovery is silent by
213
- design, and an empty row set is indistinguishable from a full recovery). Since the standing
234
+ previously-degraded monitor silently disappears — and, worse now that recovery is audible,
235
+ the mass drop-out is **indistinguishable from a full recovery**, so the panel plays the happy
236
+ **recovery chime** for every vanished monitor on a parse failure. Since the standing
214
237
  tint and the status circle are both driven by that same empty row set, a parse failure also
215
238
  **clears a standing red screen back to green** — the most reassuring possible display of a
216
239
  total loss of visibility. Recommended fix: treat "zero resources parsed" as an **error
@@ -231,6 +254,18 @@ summary, and caches ~5s. Rationale:
231
254
  alerting really wants (today the baseline resets every time a tab reloads).
232
255
 
233
256
  ## Change history
257
+ - 2026-08-14 — Generalised alert-sound synthesis and added a **recovery chime**. The old
258
+ `BEEP_COUNT`/`BEEP_HZ`/`BEEP_MS`/`BEEP_GAP_MS`/`BEEP_VOLUME` constants and the square-wave-only
259
+ `playBeeps` were replaced by a single per-role `ALERT_SOUND` table (count / freq / per-beep
260
+ `step` / duration / gap / volume / `wave`) read by a generalised `playBeeps(role)` (signature
261
+ unchanged). Retuned to degraded 3×square@720, offline 4×square@410 (was degraded 1×@720,
262
+ offline 2×@990). Recovery — a monitor dropping out of the non-operational row set — now plays
263
+ a distinct rising chime (620→800→980, freq 620/step 180) and is **audio-only by design**: no
264
+ popup, no tint (the standing tint already self-clears; a green "all clear" flash would fight
265
+ the "only shouts when wrong" design). First poll stays the silent baseline; a bad-state change
266
+ and a recovery in the same tick let the bad-state alert win. Sounds were tuned by ear in a
267
+ throwaway standalone browser "Sound Lab" (not a repo file) and ported in. Corrects the prior
268
+ "recovery is silent" and old beep-count/pitch documentation. (jcardinal)
234
269
  - 2026-08-14 — The standing (level-triggered) edge tint now **slowly breathes** its opacity
235
270
  0→1→0 on a 7s ease-in-out loop (`@keyframes alert-breathe`) instead of holding a static tint,
236
271
  so a still-broken screen draws a distant eye. The fast 0.7s `.is-blinking` event pulse still
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.587",
3
+ "version": "1.0.588",
4
4
  "description": "TOGA Technology Team Claude Knowledge System — shared AI coding harness with skills, knowledge base CLI, and project installer for Claude Code.",
5
5
  "keywords": [
6
6
  "claude",