Closed bug report

Plain toasts have never reached ah: 2.1.77 posts to /notify/toast, which Hydrogen does not serve — and a 404 was logged as "delivered"

John Lauer · 2mo ago ·closed by John Lauer

2.1.77 shipped the plain-toast mirror (#167) against a route Hydrogen has never served, and a second defect one layer down made the failure log as a success. No plain toast has ever rendered in ah. I filed and closed #167 on the strength of that false log line, so this also retracts that close.

The two defects

1. Wrong route. mirror_plain_toast_to_hd posts {kind,id,title,body,level,machine,remote,at,source} to POST /notify/toast. Hydrogen serves no such path — not on HEAD, not on the build actually running here (1.0.286, 3aee644). ah's real toast route has existed all along: POST /ui/toast {message, type?, duration?, groupId?, detail?} → hd-toast → toastStore.

So the premise on #167 — "the Hydrogen-side renderer still has to be built" — was wrong. The renderer was already there; ab was knocking on the wrong door.

2. A 404 read as success — the #168 bug, one layer lower. http_get/http_post in hd_bridge.rs called resp.json() off any response without checking the status. ah's 404 body is itself valid JSON ({"endpoints":[...],"error":"Not Found"}), so it parsed, the helper returned Ok(...), and the mirror logged TOAST-MIRROR: plain toast id=... delivered to ah. The real failure sat in a log::debug! that never fires.

This is exactly the class of bug #168 fixed for cross-box decisions: never report delivery on the strength of "the transport didn't error."

Live proof (AdomLapper, ah 1.0.286 up, control port 63549)

POST /notify/toast  -> HTTP 404  {"endpoints":[...],"error":"Not Found"}   # what ab 2.1.77 calls
POST /ui/toast      -> HTTP 200  {"ok":true,"shown":true}                  # renders, visibly

And the standing evidence in ab's own log — nine claims, zero toasts:

[11:36:19.148] TOAST-MIRROR: plain toast id=proof-2177-local delivered to ah (attempt 1)

proof-2177-local is the line I cited as the #167 proof. It was a 404.

Fix (2.1.79)

  • ah_json(resp, path): non-2xx from ah is an Err carrying the status and a body snippet. Both http_get and http_post route through it, so every ah call — permission mirror, /eval, hd_api, container exec — stops treating an error page as a value.
  • The plain-toast mirror speaks ah's actual contract: POST /ui/toast, headline/detail split, level mapped onto info|success|warning|error, remote toasts led by the origin box and held 9s, groupId: ab:<source> so a chatty bridge coalesces instead of stacking.
  • The success log now trusts ah's shown flag, not the 200; a failure is a slog line, not a debug!.

Not affected: the permission mirror (/permission/request, /permission/dismiss) posts to routes ah genuinely serves, and #164/#168 were proven end-to-end on the fleet independently of any log line.

4 Replies

John Lauer · 2mo ago

Verified on ConfRoomROG with ab 2.1.79: a plain notify_user now lands in Hydrogen (ab log: TOAST-MIRROR: plain toast id=toast-probe-279 shown in ah, and John's screenshot of the ralph level=error toast rendered red in ah). Two notes for the record.

  1. The remaining gap was Hydrogen's, not ab's. The /ui/toast route documents detail, but ah's hd-toast listener only ever read message, so ab's headline/detail split rendered as a headline with no body. Fixed in Hydrogen 1.0.287 (hydrogen-desktop f379ddc): toastStore carries detail, ToastContainer renders it as a second line, and the listener passes it through. Building now; the preprod runner gains a toast phase (t1: /ui/toast with detail shows both lines; t2: a real ab notify_user shows its body in the page).

  2. Level mapping is right: level=error painted the red error toast in ah, which is what the ralph test asked for. It reads at first glance like ah throwing an error, so a plain-toast mirror at level=error will always look alarming; that is the caller's choice, not a defect.

From Hydrogen's side #167/#169 close when 1.0.287 shows the body on a box you can see.

John Lauer · 2mo ago ·edited

Shipped as 2.1.79 (insiders), commit c5a3344d. Fleet: AdomLapper, arav-rog (boot smoke), ConfRoomROG and winvm (both taken by ah's own update handshake, not by me). Public manifest untouched at 2.1.29.

Proof — ah's DOM, not ab's log

Each leg fires a real notify_user, then asks Hydrogen's own document (POST /eval) what its toastStore rendered:

leg what ah rendered
local plain toast toast toast-info — "2.1.79 ralph: local plain toast"
level:"error" toast toast-error — "2.1.79 ralph: level=error"
remote (raised on ConfRoomROG, received here over the relay, cross_box_toasts=all) toast toast-info — "ConfRoomROG — 2.1.79 ralph: remote plain toast"

So: the route is right, the level mapping is right, and a cross-box toast leads with its origin box. test-via-gallia: 62 checks clean on the 2.1.79 relay (its three smoke notifies also rendered, gallia_t65..67).

What this proof is not

Not a pixel. Hydrogen's window was minimized on the test box for the whole run (desktop_find_window puts it at −32000,−32000 — the Windows minimized placeholder), so every hd_screenshot / CDP viewport came back blank. The DOM read is Hydrogen's own truth about what it painted, which is a level above the TOAST-MIRROR log line that fooled #167 — but the human-eyes check is still owed. Leaving this open until John sees one on screen.

Found on the way, filed separately

  • #171: after the 2.1.79 apply on AdomLapper the mesh came back without its relay, and settings_set of an unrelated key bounces the mesh.
  • The Windows CLI hands a targeted call to the local ab's egress and returns its target_not_found payload as the result instead of falling back to the relay path (cli/src/relay.rs direct_call_target → Ok(v) on any 200). Root of the "directed notify_user says target_not_found while update_status answers" confusion from the #167 close. Noted in #171 as well.
John Lauer · 2mo ago

Hydrogen 1.0.287 is shipped (wiki release + insiders manifest) and installed on ConfRoomROG and AdomLapper. Verified through the real path, not the log line: adom-bridge notify_user {title, body} on each box, then a DOM read of Hydrogen's .toast 2.5 s later:

ConfRoomROG: {found:true, hasDetail:true, text:"1.0.287 toast t2 4139 ab body 4139 should show under the headline"} AdomLapper: {found:true, hasDetail:true, text:"1.0.287 toast t2 4142 ab body 4142 should show under the headline"}

So with ab 2.1.79 and ah 1.0.287 a plain toast renders in Hydrogen with both its lines. The preprod runner now has a toast phase that fails the gate if either half regresses (t1 /ui/toast with detail, t2 a real notify_user). Nothing further owed by Hydrogen on #167/#169.

John Lauer · 1mo ago

Closing. Re-verified live today on 2.1.114 rather than on the old report, because this issue was once closed on a false log line and that is worth not repeating.

Sent notify_user {title, body} with no buttons to AdomLapper, then read Hydrogen's own DOM back through hd_api POST /eval:

["toast-container svelte-uhnbpr|AL\nPlain toast re-verify\nreverify167-21229",
 "toast toast-info svelte-uhnbpr|AL\nPlain toast re-verify\nreverify167-21229"]

toast toast-info with the probe body, in the receiver's DOM. The evidence is what Hydrogen rendered, not what ab logged.

Two notes from doing it:

  • The toast auto-dismisses quickly. My first read was ~3 s later and found an empty toast-container, which on a worse day would have read as "still broken". Poll immediately, or you will retract a working fix.
  • The AL prefix on that toast is AdomLapper's identity monogram from #180 stage 2, so that path is confirmed rendering in ah as a side effect.
John Lauer closed this · 1mo ago

Log in to reply.