What happens
On live pi.ai (probed 2026-07-04, Layer 4 CDP, headed real Chrome, dev build), opening Pi's in-chat voice menu shows only Pi's native voices (Pi 1–Pi 8). The SayPi block — Paola/Joey + the OpenAI value voices and the "More voices" door (#470/#472) — never renders. So the whole in-chat voice-choice surface on Pi is effectively dark: users can only pick Pi natives there.
Evidence (A/B — this is NOT a regression of the row refactor)
Probe: load pi.ai/talk, click the audio-controls "Toggle voice menu" button, wait for #saypi-voice-menu.expanded, dump menu state. Run against BOTH builds:
|
main baseline (d1b06bf) |
voice-menu row refactor branch |
#saypi-callButton decorated |
✅ |
✅ |
| Pi's native menu opens (Pi 1–8 visible, screenshot) |
✅ |
✅ |
#saypi-voice-menu gets .expanded |
❌ never |
❌ never |
SayPi rows / door inside #saypi-voice-menu |
0 / 0 |
0 / 0 |
Buttons inside #saypi-voice-menu (incl. host rows) |
0 |
0 |
| Console errors |
none |
none |
Identical behavior on both builds → pre-existing live defect from pi.ai DOM drift, not the refactor.
Two distinct smells in the evidence
- Expansion detection never fires.
PiVoiceMenu.addVoiceMenuExpansionListener watches .saypi-audio-controls childList for a button-with-aria-label added as firstChild. The audio controls today contain two buttons (aria-label="Turn voice off", aria-label="Toggle voice menu"); whatever Pi does on open no longer matches the firstChild-button heuristic (or the observed container has been replaced since registration — the observer would then watch a detached node).
- The element SayPi id'd as
#saypi-voice-menu is not the menu Pi actually displays. The visible Pi 1–8 list contains ZERO buttons that our diagnostics can see under #saypi-voice-menu — getVoiceMenuSelector() appears to be decorating a different (possibly stale/empty) element than the one Pi renders its voice list into.
Both need a live-DOM look (Layer 4) to re-derive Pi's current audio-controls/menu structure.
Impact
Repro
node scripts/layer4cdp.mjs verify https://pi.ai (decoration can also flake to a 25s timeout on cold mounts — that's #460), or the probe steps above; screenshots captured in the 2026-07-04 session.
What happens
On live pi.ai (probed 2026-07-04, Layer 4 CDP, headed real Chrome, dev build), opening Pi's in-chat voice menu shows only Pi's native voices (Pi 1–Pi 8). The SayPi block — Paola/Joey + the OpenAI value voices and the "More voices" door (#470/#472) — never renders. So the whole in-chat voice-choice surface on Pi is effectively dark: users can only pick Pi natives there.
Evidence (A/B — this is NOT a regression of the row refactor)
Probe: load pi.ai/talk, click the audio-controls "Toggle voice menu" button, wait for
#saypi-voice-menu.expanded, dump menu state. Run against BOTH builds:#saypi-callButtondecorated#saypi-voice-menugets.expanded#saypi-voice-menu#saypi-voice-menu(incl. host rows)Identical behavior on both builds → pre-existing live defect from pi.ai DOM drift, not the refactor.
Two distinct smells in the evidence
PiVoiceMenu.addVoiceMenuExpansionListenerwatches.saypi-audio-controlschildList for a button-with-aria-label added asfirstChild. The audio controls today contain two buttons (aria-label="Turn voice off",aria-label="Toggle voice menu"); whatever Pi does on open no longer matches the firstChild-button heuristic (or the observed container has been replaced since registration — the observer would then watch a detached node).#saypi-voice-menuis not the menu Pi actually displays. The visible Pi 1–8 list contains ZERO buttons that our diagnostics can see under#saypi-voice-menu—getVoiceMenuSelector()appears to be decorating a different (possibly stale/empty) element than the one Pi renders its voice list into.Both need a live-DOM look (Layer 4) to re-derive Pi's current audio-controls/menu structure.
Impact
Repro
node scripts/layer4cdp.mjs verify https://pi.ai(decoration can also flake to a 25s timeout on cold mounts — that's #460), or the probe steps above; screenshots captured in the 2026-07-04 session.