zebra-spaces: shadow CallFSM in the live page — log lifecycle transitions
Step 6 — first integration step. roomMachines is a real wireZebraMachines()
instance instantiated at module load (also exposed on window for DevTools
inspection). The imperative handlers still drive every side effect; this
commit only adds shadow events feeding the CallFSM so QA can see the
lifecycle in the page log AND inspect state in DevTools while we work.
Events wired:
- joinSpace → call.send('ENTER', { code, handle })
- welcome handler → call.send('WELCOME', { uuid, role })
- role-change for self → call.send('ROLE_CHANGE', { role })
- handleBlocked → call.send('BOOTED', { by: source })
- leave button → call.send('LEAVE')
- leave teardown → call.send('DONE')
An observer logs every CallFSM transition into the page log panel
('call: idle → connecting [ENTER]'), so when QA hits a defect we can
correlate the symptom with the exact state transition that fired (or
didn't fire — equally informative).
Tests stay green at 83. Next: shadow the SubscribeFSM + PublishFSMs
the same way (events only, no effects), then start swapping the
imperative paths to be FSM-driven.
This commit is contained in:
parent
d9a743a680
commit
44ac92984c
1 changed files with 25 additions and 2 deletions
|
|
@ -2281,6 +2281,23 @@ function canSpeak(role){ return role==='host' || role==='cohost' || role==='spea
|
|||
* signaling websocket — JSON text frames, see protocol header in
|
||||
* cmd/zebra-spaces-signal/main.go
|
||||
* ================================================================== */
|
||||
/* ROOM MACHINES — shadow instance. Runs alongside the imperative
|
||||
* logic during the FSM rollout: the existing handlers stay
|
||||
* authoritative for side effects, but we ALSO send synthetic events
|
||||
* here so the state machines track reality. fox can inspect via
|
||||
* `roomMachines.call.state` / `roomMachines.sub.state` in DevTools
|
||||
* during QA. As each imperative path is rewritten to be driven by
|
||||
* the FSM, the shadowing comes out. */
|
||||
const roomMachines = wireZebraMachines();
|
||||
if (typeof window !== 'undefined'){ window.roomMachines = roomMachines; }
|
||||
/* visible trace of every CallFSM transition so QA can correlate UI
|
||||
* symptoms with state changes. Will tighten the log noise once the
|
||||
* runtime takes over from the imperative handlers. */
|
||||
roomMachines.call.observe(({ state, prev, ev }) => {
|
||||
if (prev === null || state === prev) return;
|
||||
logLine('', 'call: ' + prev + ' → ' + state + (ev && ev.type ? ' [' + ev.type + ']' : ''));
|
||||
});
|
||||
|
||||
let ws = null, wantConnected = false, sigKey = null, sigReconnect = null;
|
||||
|
||||
function send(obj){ if (ws && ws.readyState===1) ws.send(JSON.stringify(obj)); }
|
||||
|
|
@ -2311,6 +2328,7 @@ async function joinSpace(){
|
|||
wantConnected = true;
|
||||
$('btn-enter').disabled = true;
|
||||
setStatus('connecting…');
|
||||
roomMachines.call.send('ENTER', { code, handle: myHandle });
|
||||
openSignal();
|
||||
}
|
||||
|
||||
|
|
@ -2344,6 +2362,7 @@ async function handleSignal(raw){
|
|||
case 'welcome':
|
||||
myUUID = m.your_uuid; myRole = m.role; roomEpoch = m.epoch;
|
||||
applyState(m.state);
|
||||
roomMachines.call.send('WELCOME', { uuid: myUUID, role: myRole });
|
||||
/* any tile auto-spotlit before welcome (during fast-path subscribe)
|
||||
* needs to be broadcast now so the room sees our viewing state */
|
||||
spotlights.set(myUUID, spotlightKey());
|
||||
|
|
@ -2472,6 +2491,7 @@ async function handleSignal(raw){
|
|||
if (m.role === 'host') hostUUID = m.uuid;
|
||||
if (m.uuid === myUUID){
|
||||
myRole = m.role;
|
||||
roomMachines.call.send('ROLE_CHANGE', { role: m.role });
|
||||
logLine('', 'you are now '+m.role);
|
||||
setStatus('connected as '+myRole, 'ok');
|
||||
const byMod = members.get(m.by);
|
||||
|
|
@ -3019,6 +3039,7 @@ function handleBlocked(source){
|
|||
if (blocked) return;
|
||||
blocked = true;
|
||||
wantConnected = false;
|
||||
roomMachines.call.send('BOOTED', { by: source });
|
||||
/* booted = clear auto-rejoin so a refresh doesn't immediately retry */
|
||||
try { sessionStorage.removeItem(ACTIVE_CALL_KEY); } catch(_){}
|
||||
try { sessionStorage.removeItem(ACTIVE_CAM_KEY); } catch(_){}
|
||||
|
|
@ -3160,6 +3181,7 @@ $('game-tabs').addEventListener('click', (ev) => {
|
|||
});
|
||||
$('btn-leave').addEventListener('click', async () => {
|
||||
wantConnected = false;
|
||||
roomMachines.call.send('LEAVE');
|
||||
/* explicit leave wipes the auto-rejoin state — user said 'out' */
|
||||
try { sessionStorage.removeItem(ACTIVE_CALL_KEY); } catch(_){}
|
||||
try { sessionStorage.removeItem(ACTIVE_CAM_KEY); } catch(_){}
|
||||
|
|
@ -3179,6 +3201,7 @@ $('btn-leave').addEventListener('click', async () => {
|
|||
$('sec-screen-share').classList.add('hidden');
|
||||
$('sec-spotlight').classList.add('hidden');
|
||||
spotlight = null;
|
||||
roomMachines.call.send('DONE');
|
||||
hideNotice();
|
||||
$('dot-call').className='dot warn';
|
||||
setStatus('left', null);
|
||||
|
|
@ -3195,8 +3218,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');
|
|||
|
||||
<footer style="margin:2.2rem auto 0;font-size:0.65rem;color:#999;line-height:1.7;word-break:break-all;font-family:monospace">
|
||||
<span id="pi-seal" style="color:#777;cursor:default;user-select:none" title="">page integrity</span> · built <span class="stamp-date">2026-06-02</span><br>
|
||||
md5 <span class="stamp-md5">4726e6221aa4643fe259cf38b6d747c9</span><br>
|
||||
sha256 <span class="stamp-sha">2b13c8c80049461809709c2ab8058f71d2bb83fe2f257a86382110e454deaa21</span><br>
|
||||
md5 <span class="stamp-md5">5b160894e031e4a9362e8fdb09bc6905</span><br>
|
||||
sha256 <span class="stamp-sha">80bdc123f6e3b3297af300b3a2076498a389bbff63042926373aa9eae7fa0a27</span><br>
|
||||
<span style="color:#bbb">hashes are of this page with these two fields zeroed — to verify, blank them and re-hash</span><br>
|
||||
<span style="color:#bbb">one self-contained file — <strong>save a copy</strong> and verify against these hashes; point at your own servers with ?signal= and ?turncred=, or <a href="host-your-own.html" style="color:#999">host your own community</a></span>
|
||||
</footer>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue