From 645db6aca7d6e43ef92ca3231936604e0d4b9e29 Mon Sep 17 00:00:00 2001 From: "russell@unturf.com" Date: Thu, 4 Jun 2026 14:22:28 -0400 Subject: [PATCH] zebra-spaces: deploy peer-booted/role-change epoch refresh (mirror) --- zebra-report/zebra-spaces.html | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/zebra-report/zebra-spaces.html b/zebra-report/zebra-spaces.html index 3c36d0b..9c2eaac 100644 --- a/zebra-report/zebra-spaces.html +++ b/zebra-report/zebra-spaces.html @@ -4236,6 +4236,11 @@ async function handleSignal(raw){ const prev = mm.role; mm.role = m.role; roomEpoch = m.epoch; + /* same gate-release as case 'state' / case 'peer-booted' — + * role-change carries a fresh epoch, so the next mod action + * (e.g. promote-then-kick) shouldn't have to wait the 1500ms + * timeout fallback before signing. */ + resolvePendingStateUpdate(); if (m.role === 'host') hostUUID = m.uuid; const subjPub = pubHexFromMsg(m, 'pubkey', 'pubkey_hex') || myKeys && (m.uuid===myUUID ? myKeys.pubHex : ''); const byPub = pubHexFromMsg(m, 'by_pubkey'); @@ -4314,6 +4319,15 @@ async function handleSignal(raw){ break; case 'peer-booted': { + /* Server bumps room epoch on every kick/ban and includes it in + * this broadcast. Pick it up + release the mod-action queue + * gate so the next kick signs against the fresh epoch — without + * this the second kick in a session hits "stale epoch". Fox + * 2026-06-04: "couldn't kick until leaving as host." */ + if (typeof m.epoch === 'number') { + roomEpoch = m.epoch; + resolvePendingStateUpdate(); + } const mm = members.get(m.uuid); const by = members.get(m.by); const victPub = pubHexFromMsg(m, 'pubkey') @@ -5870,8 +5884,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');