Closed general

desktop surface opens the Hydrogen Desktop browser window twice per drain (1.9.53)

John Lauer · 1mo ago ·closed by John Lauer

Every say --play on the desktop surface opens the Hydrogen Desktop browser window TWICE (player 1.9.53).

John noticed two browser windows appearing on his laptop each time a clip is narrated through Hydrogen Desktop's own window (the desktop surface). The caller (a cloud Claude thread) opens nothing itself: it only runs adom-tts say "<text>" --out <file> --thread <t> --desc <d> --play --confirm with no --surface, and the player fell through to desktop because the cloud editor tab was not live.

adom-tts logs shows the double open at every drain start, same target, same URL, same second:

   787s ago  pid=1184521 drain_start surface="desktop"
   786s ago  pid=1184521 desktop_window_opened target="AdomLapper" url="https://john-galliaapril-8v0y8o3547h2.adom.cloud/proxy/39607/"
   786s ago  pid=1184521 desktop_window_opened target="AdomLapper" url="https://john-galliaapril-8v0y8o3547h2.adom.cloud/proxy/39607/"
   781s ago  pid=1184521 clip_start clip="answer-crr.mp3" id=1 port=39607 surface="desktop"
   ...
   303s ago  pid=1189956 drain_start surface="desktop"
   302s ago  pid=1189956 desktop_window_opened target="AdomLapper" url="https://john-galliaapril-8v0y8o3547h2.adom.cloud/proxy/39607/"
   302s ago  pid=1189956 desktop_window_opened target="AdomLapper" url="https://john-galliaapril-8v0y8o3547h2.adom.cloud/proxy/39607/"

The run from six days ago (pid 3282234, same container, same target) logged desktop_window_opened once per drain, so this is a regression in the current player. The clips themselves play fine (verdict="ok"), it is only the second window.

Two asks:

  1. Open the desktop window once per drain (or check for an existing player window on that URL before opening).
  2. If the second open is a deliberate retry (for example the first open's ack was slow), log it as a retry with the reason, so the log does not read as two opens of the same page.

Container: john-galliaapril-8v0y8o3547h2, adom-tts 1.9.53, 2026-09-18.

1 Reply

John Lauer · 1mo ago

Fixed in adom-tts 1.9.54. Both asks.

What was happening: at drain start the player opens the surface once, then the audience wait (the loop that waits for the page to poll before the first clip) offers the surface again on its very first iteration when the page is not live yet. A webview tab absorbs that (open-or-refresh by name) and a pup session just navigates, but a Hydrogen Desktop window is a new window every time, and a fresh one takes a few seconds to load and poll, so the second offer always landed. The six-days-ago run opened once only because the page from the previous drainer was already polling on that port. Not a regression in 1.9.53 as such: the desktop surface is the first one where the double offer is visible.

  1. One open per drain: surface opens are now debounced process-wide (one successful open per 10 seconds). The audience wait's first offer after the startup open becomes a no-op and is logged as surface_open_skipped with how long ago the open succeeded. A clip that arrives later against a page that has really gone silent still gets a re-offer, so recovery is unchanged.

  2. Retries say so: every offer after the first logs surface_reoffer {attempt, reason: "page has not polled for Ns"} before opening, so the log reads as one open plus named retries, never two opens of the same page. The mid-clip rescue already logged player_reopen with the poll age.

Harness T13 now delays its fake page by six seconds and asserts exactly one hd_api POST /hbw/open per drain plus the skipped event. Against the shipped 1.9.53 binary that check goes red (two opens, no skipped event); on 1.9.54 it is green, 30 of 30. Two harness defects hid this until now: the fake page answered instantly (a real Hydrogen Desktop window does not), and the fake page was an orphaned child that kept polling the reused port after its test ended, so the next drainer always saw a live page. Both fixed in the same release.

Not done, and worth knowing: the drainer still does not ask Hydrogen Desktop whether a player window on that URL already exists before opening, because I could not find a list or focus endpoint under /hbw on the control API from here (the bridge relay showed no targets when I checked). If Hydrogen exposes one, a follow-up can make the open idempotent on the desktop side too. Also the log from last night shows the bridge for AdomLapper dropping off the relay at 22:40, which is why later opens failed with "No connected Adom Bridge matches"; that is the relay, not this fix.

Log in to reply.