# How Hydrogen Desktop Auto-Updates

Hydrogen Desktop keeps itself, its skills, and its content current from the Adom Wiki. This
page is the canonical inventory of every mechanism that phones home: what it fetches, when,
how big the payload is, and how the schedules are designed so a large fleet cannot
accidentally denial-of-service the wiki with synchronized requests.

## The mechanisms

| # | What updates | Trigger and cadence | Endpoint | Payload |
|---|---|---|---|---|
| 1 | **The HD app itself** | 20 s after launch, then every 4 h (launch-anchored timer) | `version.json` on this page | ~1 KB manifest; the ~100 MB signed installer downloads ONCE per new version, SHA-256 verified, background-staged |
| 2 | **Lightbulb prompt list** | Opening the menu (debounced to 15 min) plus a background tick every 30 min that fetches only if 4 h stale AND Mon-Fri 7am-7pm local; manual refresh button bypasses the debounce | `lightbulb-prompts/prompts.json` on this page | ~10 KB |
| 3 | **Workspace packages + skills** (inside the container) | The registry hook runs `adom-wiki pkg update` on user activity, throttled to ~30 min; nothing fires while the machine is idle | wiki package registry | manifests are KBs; package tarballs only when versions changed |
| 4 | **code-server drift check** | After launch: 90 s cadence for a short early window, then every 30 min | workspace-internal, wiki only if drift found | tiny |
| 5 | **Adom Desktop + its bridges** (AD is its own app) | On AD launch, then every 4 h per bridge page | each bridge's wiki page | manifests; binaries only on version change |
| 6 | **Setup cascade** (one-time) | The `update-packages` step runs once per install/setup, not periodically | wiki package registry | whatever the image is behind by |

Update mode for #1 is user-controlled (Settings → Hydrogen Desktop → Updater): Normal shows a
banner and you choose when to restart; Forced is reserved for important fixes; Off disables
the check entirely.

## Why the fleet cannot DoS the wiki (design rules)

1. **Every periodic timer is launch-anchored, not wall-clock-anchored.** A 4 h timer starts
   counting from the moment that particular machine launched HD. Launches are naturally
   spread out, so across a fleet the polls are approximately uniformly distributed in time.
   No timer fires "at the top of the hour" by design.
2. **Manifests are tiny, binaries are fetched once.** The recurring traffic is 1-10 KB
   manifest reads. The heavy installer download happens exactly once per released version per
   machine, gated by a SHA-256 comparison, and is spread across each machine's next 4 h poll
   window rather than all at once.
3. **Activity gating.** The container package hook fires on user prompts (throttled), so idle
   machines generate no traffic. The lightbulb background tick is additionally gated to
   business hours, and any user-driven check (menu open) debounces to 15 minutes and
   satisfies the background timer's freshness window too, so the two paths never double-poll.
4. **Cloudflare fronts the wiki.** The static file and download paths are CDN-cacheable, so
   even a correlated read burst of the same manifest mostly terminates at the edge.
5. **Releases are gated before they are advertised.** The release pipeline refuses to publish
   a `version.json` that points at a missing installer (HEAD-checked first), so the fleet is
   never sent chasing 404s on a retry loop.

## Known herding risks (honest list, with status)

- **Phase alignment after an update wave.** When a release ships and the whole fleet
  restarts within a short window, every machine's launch-anchored 4 h timer becomes roughly
  phase-aligned and stays that way until the next uncorrelated restart. A fleet of N then
  polls the ~1 KB manifest in a burst every 4 h. At current fleet sizes this is noise, and
  the CDN absorbs it; at much larger scale the fix is jitter (below).
- **Morning boot storms.** Office machines powered on together Monday 9am launch together,
  which briefly correlates the launch-anchored timers. Same magnitude and mitigation as
  above.
- **The business-hours gate clusters its opens.** The lightbulb tick's Mon-Fri 7am-7pm gate
  means the subset of machines whose 30 min tick lands just after 7am local all fetch within
  that first half hour. Bounded by the tick spread, ~10 KB each, per timezone.
- **Planned hardening (not yet implemented):** add ±10-15% random jitter to the fixed
  intervals (HD updater, lightbulb tick, AD bridge sync), send `If-None-Match`/ETag on
  manifest reads so unchanged polls are 304s, and if the fleet grows large, stagger releases
  by advertising `version.json` to cohorts instead of everyone at once. Also planned: relax
  the app updater's 4 h poll to **every 24 h** once the release cadence settles (John
  2026-07-24) — the 4 h cadence serves today's rapid pre-release iteration; a shipping
  product needs at most a daily check, which also cuts the fleet's steady-state traffic 6x.

## For contributors

If you add ANY new periodic fetch to HD, follow the design rules above (launch-anchored,
debounced, activity- or hours-gated where sensible, tiny manifest + fetch-once binary) and
add it to the table on this page in the same PR.
