Files
werkregie/doc/prs/2026-10-12-PR#52-robust-reload.md
2026-10-12 21:39:53 +02:00

6.5 KiB

PR#52: The Page Loads Robustly After Waking Up and Shows a Late Relay

WARNING: This document describes only the change applied in this PR. It may already be outdated once the next PR is merged. Historic PR documentation is not maintained along with new PRs; treat it as a snapshot.

Problem

On the phone, the installed page showed only one entry under "Du bist dran" after waking up, a PR; several sessions of Claude Code were waiting. A manual reload showed all of them.

The cause is not certain; two candidates:

  1. The page loaded during the deployment at 18:07, while server and relay restarted; the relay think reported again only about 13 s later. A relay that is late or missing is not visible in the header: its sessions are silently missing.
  2. After waking up, the network was not ready; the first load() failed or hung, and the page kept the old state. load() runs on visibilitychange and every 5 s; a request that hangs never ends, and a return from the back/forward cache fires no visibilitychange.

Non-Goals

  • No new server endpoint and no push channel; the page keeps polling.
  • No change of relayStaleSeconds or relayGoneSeconds.
  • No memory of the relays in the browser; the server alone knows which relays report.

Specification

Feature: the page loads the current state after waking up

Scenario#52.01: a return to the page loads at once

… so that a page from the back/forward cache does not show an old state for 5 s.

  • Given the user left the page, and the browser kept it in its back/forward cache
  • When the user goes back to the page
  • Then the page asks the server at once
Verified by
  • Manual: see "Check in the Browser".

Scenario#52.02: the network coming back loads at once

… so that the page shows the current state as soon as it can.

  • Given an open page whose last load failed
  • When the network is back (online)
  • Then the page asks the server at once
Verified by
  • Manual: see "Check in the Browser".

Scenario#52.03: a failed load is retried after 1 s

… so that a network that is not ready yet after waking up costs 1 s, not 5 s.

  • Given an open page that showed the current state
  • When the server does not answer one load because the network is not ready
  • Then the page asks the server again after 1 s instead of 5 s
Verified by
  • Manual: see "Check in the Browser".

Scenario#52.04: a hanging request counts as failed

… so that a dead connection after waking up does not keep the old state.

  • Given an open page
  • When the server does not answer within 10 s
  • Then the page aborts the request and shows "offline"
Verified by
  • Manual: see "Check in the Browser".

Scenario#52.05: an older answer does not replace a newer one

… so that two loads at the same time, e.g. on pageshow and visibilitychange, do not show an old state.

  • Given two loads in progress
  • When the answer of the first one arrives after the answer of the second one
  • Then the page ignores the answer of the first one
Verified by
  • Manual: see "Check in the Browser".

Feature: the header shows a late or missing relay

Scenario#52.06: a late relay shows in the header

… so that sessions that are missing or old do not go unnoticed.

  • Given the relay think, silent for longer than relayStaleSeconds
  • When the page shows the answer of the server
  • Then the indicator in the header shows "think still" in amber, with the time of its last report as tooltip
Verified by
  • RelayRegistryTest: the existing tests of the silent status.
  • Manual, for the header: see "Check in the Browser".

Scenario#52.07: a server without any relay shows it

… so that a lost relay state, e.g. after a deployment, does not look like a quiet day.

  • Given a server whose relay registry is empty
  • When the page shows the answer of the server
  • Then the indicator in the header shows "kein Relay" in amber, and the sources list a failing "Relays"
Verified by
  • RelayRegistryTest: "an empty registry reports that no relay reports".
  • Manual, for the header: see "Check in the Browser".

Check in the Browser

The dashboard 0.32.0 ran in server mode with relayStaleSeconds: 8 in Claude's browser pane; curl posted the reports of a relay think, and a stand-in for fetch failed, hung or delayed the answers.

  • Without any relay, the header showed "no relay" in amber, the overview "Relays: kein Relay meldet" (#52.07).
  • With fresh reports it showed "live"; 8 s after the last report "think silent" in amber, with "Relay think: last seen 29 s ago" as tooltip (#52.06).
  • At 375 px width the header showed "THINK SILENT" in amber beside its dot, without a horizontal scroll bar.
  • online and a pageshow with persisted each loaded at once; a pageshow without persisted did not (#52.01, #52.02).
  • Both failing at once: the page loaded again after 1, 2 and 3 s, then no more; it showed "offline" and the banner (#52.03).
  • A request that never ended: "live" after 9 s, "offline" after 10.5 s (#52.04).
  • Of two loads at once, the first answered 1.5 s after the second; the page kept the answer of the second (#52.05).

Solution

  • load() aborts its request after 10 s with AbortSignal.timeout, where the browser has it.
  • After a failure, load() sets one retry after 1 s, at most 3 in a row; two loads that fail at once share it. Any load cancels a pending retry, since it takes its place.
  • visibilitychange, pageshow from the back/forward cache and online call loadAfterWaking(): it resets the retries, which a failure before sleeping may have used up.
  • Each load has a number; an answer older than the one shown is ignored.
  • setLive() shows the late relays instead of "live", in amber: a relay with silent, or "kein Relay". On a phone the indicator otherwise shows its dot only; for a late relay it shows its text, too.
  • RelayRegistry.statuses() reports a failing status relays with "kein Relay meldet" when it holds no relay. So the overview and the tab Quellen show it, too, through the existing connections().
  • Version 0.32.0; PR#51 holds 0.31.0.

Open Questions

  • TODO.js-tests: the loading and the header are checked only by hand; the repository has no runtime for tests of the page's JavaScript, and a new one needs the consent of the human.