Closed general

2.1.94: buttoned notify_user no longer mirrors to Hydrogen as a notify-decision card (local, cross-box, and with focus host:true); plain toasts still mirror

John Lauer · 2mo ago ·closed by John Lauer

Measured 2026-09-10 14:39-14:45 UTC on ab 2.1.94 (ConfRoomROG and winvm), Hydrogen 1.0.322 on ConfRoomROG, mesh up (3 peers, relay connected).

A buttoned notify_user no longer reaches the embedded Hydrogen as a notify-decision card. Three shapes, all "status ok, action displayed" in ab, none produced a POST /permission/request on Hydrogen (its hd log shows only the two plain /ui/toast mirrors in that window, and the page had zero .perm-card elements):

  1. local on ConfRoomROG: {id badge-proof-322b, scenario reminder, buttons [Looks right, Skip]}
  2. cross-box from winvm: {id badge-x-322, scenario reminder, same buttons}
  3. local on ConfRoomROG with focus {host:true}: {id badge-host-322}

Plain toasts (no buttons) mirror fine and now carry originIdentity as agreed on #180 (Hydrogen 1.0.322 paints the badge in the bell; see adom/hydrogen#72). On 2.1.88 the 2026-09-09 circuit proved buttoned toasts arriving as decision cards on every box, local and mesh, and the ab thread's own "2.1.94 proof: which box is this from?" from winvm did arrive on ConfRoomROG at 14:30 UTC as a decision card. So either the mirror wants a field my three calls lacked (say which and I will use it in the harness), or the buttoned mirror regressed between that call and 14:39. Repro: any of the three calls above against a box with Hydrogen open, then GET /logs/tail on that Hydrogen and grep permission/request.

4 Replies

John Lauer · 2mo ago

Reproduced from winvm with your exact shape (scenario reminder, buttons as objects, no wait): ab answers displayed, and NOTHING is mirrored - no MIRROR line on the laptop, no card. Cause, not a 2.1.93/94 regression: notifications.rs mirrors a buttoned toast as a notify-decision card only when wait:true (decision_prompt = payload.wait && !buttons.is_empty()), and mirrors a plain toast only when it has NO buttons - so a buttoned toast raised without wait mirrors nowhere. Every proof that 'worked' (the 2026-09-09 circuit, my 2.1.94 proof) passed wait:true. Workaround for your harness today: add wait:true (and a timeoutSeconds). Fix coming as 2.1.96: a buttoned toast is registered and mirrored as a decision card whether or not the caller waits; a decision made in Hydrogen or on another box records the notify_response exactly as a click on the origin box does, so a polling caller sees it.

John Lauer · 2mo ago

Fixed in 2.1.96 (insiders; winvm canary, then ConfRoomROG and AdomLapper). Cause was the GATE, not the transport: decision_prompt was payload.wait && !buttons.is_empty(), and the plain-toast mirror skips any toast that HAS buttons, so wait:false + buttons entered no mirror at all while ab still answered action:displayed. It is now !buttons.is_empty(), and that Vec is built from BOTH request shapes (structured buttons:[{label}] and simple actions:[label]), so your three calls and my repro take the same path. Second flaw caught before shipping: the teardown (forget_notify_decision + permission_mirror::dismiss + shell-approval-dismiss) sits immediately after the wait loop, so simply widening the gate would have mirrored the card and dismissed it in the same instant. The teardown is now the waiting path's; a non-waiting prompt gets a watcher after its result is on the wire that polls has_notify_response (non-destructive, so the answer stays for your notify_response poll) up to the card lifetime, then retires every copy. A non-waiting card advertises 600 s instead of 60 s, matching the toast that sits in the notification centre. Proof on ConfRoomROG (ab 2.1.96, ah 1.0.322), image attached: your shape 1 (local, scenario reminder, buttons objects, no wait) and shape 2 (same from winvm) BOTH render as decision cards in Hydrogen, with 1.0.322's badges - orange WI cloud for winvm, purple CR laptop for the local one - and Hydrogen's header reads 2 approvals waiting. Note for your harness: hd_eval is dev-only in the public build (verb_moved_to_hd_dev); hd_api is the pass-through, and ah's control API has no /permission/state, so DOM counting needs the hd-dev build or a screenshot.

shot-2196-hd

John Lauer · 2mo ago

Second half proven: the non-waiting cards are not immortal. Same two cards, same Hydrogen, 11 minutes later (raised 10:30:39 and 10:30:52 with the 600 s life, screenshot at 10:41:40): both gone, Hydrogen's '2 approvals waiting' chip cleared, and ab's own permission stack on ConfRoomROG reports no repro182 card. So the watcher retires every copy - ab's stack, Hydrogen, the peers - when the lifetime runs out, exactly as the waiting path does when it times out. Fleet is on 2.1.96 (winvm canary through the real embedded update path, then ConfRoomROG and AdomLapper); Linux CLI 2.1.96 published and gallia's relay module refreshed. Closing once the smoke suite reports clean.

shot-2196-expired

John Lauer · 2mo ago

Closing: 2.1.96 insiders on the whole fleet, both halves proven on ConfRoomROG with ah 1.0.322 (cards appear for non-waiting buttoned toasts, local and cross-box, with the right badges; and they retire everywhere when the lifetime runs out); smoke suite on 2.1.96: 60/60 executed, 0 unexpected failures.

John Lauer closed this · 2mo ago

Log in to reply.