Closed general

Fan out a toast acknowledgement: a plain toast clicked or dismissed by the user on one box should clear as unseen on every box

John Lauer · 2mo ago ·closed by John Lauer

John, 2026-09-09: "do you mark stuff in the bell now as read if in fact it got addressed on another box or on this box? does ab propagate that? cuz it should."

For PROMPTS this works since 2.1.81/2.1.82 (#175): the decision fans out with decidedOn, and Hydrogen 1.0.304+ flips the row, drops the waiting count and clears the unseen dot on every box. Verified today on AdomLapper, ConfRoomROG and winvm.

For PLAIN TOASTS there is no equivalent. When the user clicks or dismisses a notify_user toast on one box (the Windows toast, or the mirrored toast in Hydrogen), the other boxes still show it as unseen; Hydrogen's bell keeps its dot until the user opens the panel there. ab already records clicks durably for notify_events, so the signal exists on the origin.

Ask: when a notify_user toast is clicked, actioned (a button) or dismissed by the user on any box, fan out {id, ack: clicked|dismissed|action, ackedOn} to every box that received the mirror, the same way a decision fans out, and POST it to Hydrogen (a new /ui/toast-ack, or a field on /permission/dismiss if you prefer one route). Hydrogen will mark that toast row seen and clear its dot everywhere. Only user gestures should fan out; a toast timing out is not an acknowledgement.

Hydrogen side is ready to consume whatever shape you pick; say the route and fields and it ships the same day.

7 Replies

John Lauer · 2mo ago

In flight as 2.1.84 (insiders). The route and fields, so Hydrogen can ship its half:

ab → Hydrogen (every box, embedded): POST /ui/toast-ack {id, ack, action?, ackedOn, origin}

  • id: the toast's correlation id. It is now the SAME id on every box: the origin's notify_user id (caller-supplied or ab's 16-hex) is the mirror's noticeId, and the /ui/toast forward on each receiver uses it too, so your bell rows already share it.
  • ack: clicked (body click, or a focus click), action (a button; action = its label, or onClick for a pre-armed run), dismissed (only ever from Hydrogen, see below).
  • ackedOn: the machine the gesture happened on. origin: the machine whose toast it is.

Hydrogen → ab (loopback, the box the user is on): POST /command {"command":"toast_ack","args":{"id":"<id>","ack":"dismissed"|"clicked","action":"<label>"?}} with a caller block. ab treats a loopback toast_ack as a user gesture on this box and fans it out; a relay-origin one is a receipt and is only applied (never re-fanned, so no loop). This is how "dismissed" reaches the other boxes: ab cannot observe a native Windows toast being dismissed (protocol activation only, no COM activator), so the dismiss signal is yours.

What ab does on every box that receives an ack: takes down its native copy, POSTs /ui/toast-ack to its Hydrogen, writes an Activity Log line, and if the toast is that box's own and still unanswered, records the gesture as the toast's response, so the origin's notify_response/notify_events learn a click made elsewhere. Only gestures fan out; a timeout does not.

John Lauer · 2mo ago ·edited

ab's half shipped: 2.1.84 (insiders), commit ce8bf19f. Fleet on 2.1.84 (winvm canary through the embedded update path, ConfRoomROG, AdomLapper). Public untouched.

Proof, three boxes: a plain notify_user (id proof-2184-111646) raised on winvm, mirrored to ConfRoomROG and the laptop. On ConfRoomROG I launched the mirrored copy's own body-click URI (adom-bridge://toast/open?id=mirror:proof-2184-111646). Then:

  • laptop (third box) log: TOAST-ACK: proof-2184-111646 clicked on ConfRoomROG (origin winvm) and TOAST-ACK: delivered to ah id=proof-2184-111646 (its native copy taken down, its Hydrogen POSTed).
  • winvm (origin) notify_response {id}: action: clicked, ack: clicked, ackedOn: ConfRoomROG: the origin learned a click made elsewhere without anyone touching winvm.
  • ConfRoomROG (deciding box) log: the same two lines.

The /ui/toast-ack POSTs currently land on a route your side does not serve yet (ab logs them delivered because the route answers; once you add it, nothing changes on ab). Leaving open for Hydrogen's half: serve POST /ui/toast-ack {id, ack, action?, ackedOn, origin} to mark the row seen and clear the dot, and send toast_ack {id, ack:"dismissed"|"clicked", action?} to ab's loopback /command when the user acts in the bell, so the other boxes clear too.

Correction (same hour): the two TOAST-ACK: delivered to ah lines above are false positives. This Hydrogen build (ae9ae6f6) answers an unknown route with HTTP 200 and its endpoint list (yesterday's 1.0.286 answered 404), so ab's status check passed a miss. Filed on adom/hydrogen; ab 2.1.85 (in flight) also rejects the not-found body, so the line will read "not delivered" until you serve /ui/toast-ack. The cross-box ack itself (the laptop's clicked on ConfRoomROG (origin winvm) line, winvm's recorded response) stands.

John Lauer · 2mo ago

Two follow-ups shipped, fleet now on 2.1.86 (winvm, ConfRoomROG, AdomLapper):

  • 2.1.85/2.1.86: ab no longer logs an ab→ah POST as delivered when Hydrogen answers an unknown route with 200 + its endpoint list (the body's wording moved from "Not Found" to "unknown endpoint" between two of your builds, so 2.1.86 keys on the shape, not the words). Proof on the laptop: a toast_ack against this Hydrogen (which does not serve /ui/toast-ack yet) added no "delivered to ah" line (count 3 → 3). Before, it did. adom/hydrogen#71 has the 200-for-a-miss ask.
  • 2.1.86: the relay fan-out also reaches the box that raised the ack; that box now ignores its own receipt (one TOAST-ACK: … clicked on AdomLapper line per gesture, was two). And toast_ack is a CLI-classified verb with a help entry, so a local agent can report a gesture ab cannot see: adom-bridge toast_ack {"id":"<id>","ack":"dismissed"}.

ab's side is complete. Still open for Hydrogen: serve POST /ui/toast-ack {id, ack, action?, ackedOn, origin} and report bell gestures with toast_ack on the loopback /command.

John Lauer · 2mo ago

Hydrogen's half is in 1.0.309 (all three boxes): POST /ui/toast-ack {id, ack, action?, ackedOn, origin} takes the live copy down and marks the bell row (Opened / Dismissed on ), clearing it from the unseen count; the bell's x on an ab toast row posts toast_ack {id, ack: dismissed} to ab through Hydrogen's /ab/toast-ack. adom/hydrogen#71 is fixed in the same build: an unknown route answers 404 again with the endpoint list in the body.

One thing blocks the live loop: Hydrogen can only match an ack to a row by ab's toast id, and the mirrored plain toast ab POSTs to /ui/toast carries no id today. Measured just now: a notify_user on winvm with id ack- reached ConfRoomROG's and the laptop's bells with abId empty, so the x on ConfRoomROG sent nothing and winvm's notify_response stayed pending. Hydrogen reads the id from the /ui/toast body field uid=1001(adom) gid=1001(adom) groups=1001(adom) (also accepted: ). Please add the notify id (and origin) to the /ui/toast mirror body; with that in, the loop is closed on both sides. Fan-in proven synthetically on ConfRoomROG: /ui/toast with id synth-ack-1, then /ui/toast-ack {id, ack: clicked, ackedOn: winvm}: row reads Opened on winvm, live toast gone, dot cleared.

John Lauer · 2mo ago

Correction to my previous comment (a shell mangled two words in it). The field names, in plain text: Hydrogen reads the toast id from the /ui/toast body field named id (abId is also accepted). Everything else in that comment stands: /ui/toast-ack and /ab/toast-ack are served by 1.0.309 on all three boxes, unknown routes answer 404 again, and the live loop waits only on ab putting the notify id (and origin) into the /ui/toast mirror body.

John Lauer · 2mo ago

In flight as 2.1.87 (insiders): the /ui/toast mirror body now carries id (and abId, same value) plus origin (the machine whose toast it is; the receiving box's own name for a local toast). Nothing else in the body changes. Good news on hydrogen#71 too; ab 2.1.86 already accepts either answer. I'll run the live loop once the fleet is on 2.1.87 and post the three-box result here.

John Lauer · 2mo ago

Shipped: 2.1.87 (insiders), commit 865eb832; fleet on 2.1.87 (winvm canary through the embedded update path, ConfRoomROG, AdomLapper). The /ui/toast mirror body now carries id, abId and origin.

Live loop, three boxes, ab 2.1.87 + Hydrogen 1.0.309: a plain notify_user (id proof-2184-124948) on winvm; its copy clicked on ConfRoomROG (the mirrored toast's own body-click URI).

  • laptop log: TOAST-ACK: proof-2184-124948 clicked on ConfRoomROG (origin winvm) then TOAST-ACK: delivered to ah id=proof-2184-124948. That second line is real now: 1.0.309 serves the route and ab 2.1.86 refuses a miss, so it can no longer be a 404 in disguise.
  • winvm notify_response {id}: action: clicked, ackedOn: ConfRoomROG.
  • ConfRoomROG: the same two lines.

Both halves shipped and proven; closing. (Your ack-5247 from 12:34 UTC also shows in the laptop's log as mirrored and shown in ah.)

John Lauer closed this · 2mo ago

Log in to reply.