diff --git a/hub/CHANGELOG.md b/hub/CHANGELOG.md index 1cadf226..8e49e1a8 100644 --- a/hub/CHANGELOG.md +++ b/hub/CHANGELOG.md @@ -10,7 +10,7 @@ - **D30 (R-1204).** The agent's re-key (felhom-agent `ae69ad4`) registers the new key on `POST /hosts//wg` (re-key in place, unchanged); the new key's first handshake clears `wg_tunnel_stale` once — pinned by `TestD30_TheAlarmClearsWhenTheNewKeyShakesHands` (red-proved). The stale text says an agent with D30 re-keys by itself - within about 15 minutes; the `wg_tunnel_ok` log line is INFO; the source comment no longer says the ok event is + 15 minutes after it sees the sign, plus its next desired-state fetch; the `wg_tunnel_ok` log line is INFO; the source comment no longer says the ok event is mailed (it is stored, not mailed — review 2026-10-22 night). - `scripts/wire_contract_gate.py`: `wireguard.last_handshake_age_s` left the unread list (the hub reads it since 0.166.0). diff --git a/hub/internal/api/host_tunnel.go b/hub/internal/api/host_tunnel.go index 11a53451..0e4c2b8d 100644 --- a/hub/internal/api/host_tunnel.go +++ b/hub/internal/api/host_tunnel.go @@ -39,7 +39,7 @@ func wgTunnelStale(w *hostWireguard) (bool, string) { return false, "" } if w.HandshakeFutureS != nil && *w.HandshakeFutureS > 0 { - return true, fmt.Sprintf("its last handshake is stamped %s in the FUTURE by the box's own clock — the clock ran ahead once, and ep0 refuses every newer handshake until that time passes (an agent with the D30 repair makes a new key by itself within about 15 minutes)", humanDuration(*w.HandshakeFutureS)) + return true, fmt.Sprintf("its last handshake is stamped %s in the FUTURE by the box's own clock — the clock ran ahead once, and ep0 refuses every newer handshake until that time passes (an agent with the D30 repair makes a new key by itself: 15 minutes after it sees this, plus its next desired-state fetch)", humanDuration(*w.HandshakeFutureS)) } if w.LastHandshakeAgeS != nil && *w.LastHandshakeAgeS > wgTunnelStaleAfterS { return true, fmt.Sprintf("it has not shaken hands for %s while the box reports — the box's clock may have run ahead (then ep0 refuses it), or ep0 dropped the peer", humanDuration(*w.LastHandshakeAgeS))