code wiki / _hdl_build / nx_room_waitlobby.nx
nx_room_waitlobby.nx source
↩ module page · 133 lines · 6718 B
1// nx_room_waitlobby.nx -- X-ROOM (GEN-ROOM-waiting-room-lobby): sovereign
2// DETERMINISTIC admission-control FSM for the room's PRO-mode waiting room
3// (lobby). Participants KNOCK; the host ADMITs / DENYs / ADMIT_ALLs; the room
4// can be LOCKed (closed). Every transition is a reproducible, auditable verdict.
5//
6// EXCEED axis (honest) vs Zoom/Whereby waiting rooms: deterministic + audit-
7// replayable admission -- replay the same event stream, get the same admitted set
8// -- plus two integrity invariants a loose implementation can violate:
9// (I1) a host can only ADMIT/DENY someone who actually KNOCKED (no admitting a
10// ghost id = no silent gate-crash),
11// (I2) a KNOCK while the room is LOCKED is closed-out (DENIED) deterministically,
12// not racily admitted.
13// Pro waiting-room (explicit admit) is the DATA-distinct sibling of personal
14// instant-join; this organ is the explicit-admit half.
15//
16// status codes: 0=UNKNOWN 1=KNOCKING 2=ADMITTED 3=DENIED ; status[0] = locked flag.
17// event codes: 1=KNOCK 2=ADMIT 3=DENY 4=ADMIT_ALL 5=LOCK 6=UNLOCK.
18//
19// main() is the SELF-VALIDATING GATE. Evidence -> knowledge/status/room_waitlobby.log.
20// license_tier: ORIGINAL
21import "nx_syscalls.nx"
22
23const WL_LOG: *u8 = "knowledge/status/room_waitlobby.log"
24const WL_UNKNOWN: i64 = 0
25const WL_KNOCKING: i64 = 1
26const WL_ADMITTED: i64 = 2
27const WL_DENIED: i64 = 3
28
29func ww(fd: i64, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(fd, s, n); return 0 }
30func wwn(fd: i64, v: i64) -> i64 { let bb: *u8 = sys_mmap(28); var m: i64=v; if m<0 {m=0-m; sys_write(fd,"-" as *u8,1)}; let t: *u8 = sys_mmap(28); var k: i64=0; if m==0 {t[0]=48;k=1}; while m>0 {t[k]=(48+(m%10)) as u8; m=m/10; k=k+1}; var i: i64=0; while i<k {bb[i]=t[k-1-i]; i=i+1}; sys_write(fd, bb, k); return 0 }
31
32// process an ordered event stream into a fresh status array (index 0 = locked flag).
33// maxid participants 1..maxid. evt[]/eid[] are the event code and target id.
34func wl_run(maxid: i64, evt: *i64, eid: *i64, nev: i64, status: *i64) -> i64 {
35 var i: i64 = 0
36 while i <= maxid { status[i] = WL_UNKNOWN; i = i + 1 } // status[0]=locked=0
37 var e: i64 = 0
38 while e < nev {
39 let code: i64 = evt[e]
40 let id: i64 = eid[e]
41 if code == 1 { // KNOCK
42 if status[0] == 1 { status[id] = WL_DENIED } // I2: locked -> closed out
43 else { if status[id] == WL_UNKNOWN { status[id] = WL_KNOCKING } }
44 }
45 if code == 2 { // ADMIT (I1: only a knocker)
46 if status[id] == WL_KNOCKING { status[id] = WL_ADMITTED }
47 }
48 if code == 3 { // DENY (only a knocker)
49 if status[id] == WL_KNOCKING { status[id] = WL_DENIED }
50 }
51 if code == 4 { // ADMIT_ALL knockers
52 var j: i64 = 1
53 while j <= maxid { if status[j] == WL_KNOCKING { status[j] = WL_ADMITTED } j = j + 1 }
54 }
55 if code == 5 { status[0] = 1 } // LOCK
56 if code == 6 { status[0] = 0 } // UNLOCK
57 e = e + 1
58 }
59 return 0
60}
61
62func wl_count(maxid: i64, status: *i64, want: i64) -> i64 {
63 var c: i64 = 0
64 var i: i64 = 1
65 while i <= maxid { if status[i] == want { c = c + 1 } i = i + 1 }
66 return c
67}
68
69func main() -> i64 {
70 let evt: *i64 = sys_mmap(8 * 32) as *i64
71 let eid: *i64 = sys_mmap(8 * 32) as *i64
72 let st: *i64 = sys_mmap(8 * 16) as *i64
73 var ok: i64 = 1
74 let MAXID: i64 = 9
75
76 // timeline: 3 knock(open)->admit1,deny2,admit3 ; admit-ghost9(ignored) ; LOCK ;
77 // knock4,knock5(locked->denied) ; UNLOCK ; knock6,knock7 ; ADMIT_ALL
78 var n: i64 = 0
79 evt[n]=1; eid[n]=1; n=n+1
80 evt[n]=1; eid[n]=2; n=n+1
81 evt[n]=1; eid[n]=3; n=n+1
82 evt[n]=2; eid[n]=1; n=n+1 // admit 1
83 evt[n]=3; eid[n]=2; n=n+1 // deny 2
84 evt[n]=2; eid[n]=3; n=n+1 // admit 3
85 evt[n]=2; eid[n]=9; n=n+1 // admit ghost 9 -> IGNORED (never knocked)
86 evt[n]=5; eid[n]=0; n=n+1 // LOCK
87 evt[n]=1; eid[n]=4; n=n+1 // knock 4 while locked -> DENIED
88 evt[n]=1; eid[n]=5; n=n+1 // knock 5 while locked -> DENIED
89 evt[n]=6; eid[n]=0; n=n+1 // UNLOCK
90 evt[n]=1; eid[n]=6; n=n+1 // knock 6
91 evt[n]=1; eid[n]=7; n=n+1 // knock 7
92 evt[n]=4; eid[n]=0; n=n+1 // ADMIT_ALL -> 6,7 admitted
93 wl_run(MAXID, evt, eid, n, st)
94
95 let adm: i64 = wl_count(MAXID, st, WL_ADMITTED)
96 let den: i64 = wl_count(MAXID, st, WL_DENIED)
97 let kno: i64 = wl_count(MAXID, st, WL_KNOCKING)
98 if adm != 4 { ok = 0 } // 1,3,6,7
99 if den != 3 { ok = 0 } // 2 (denied) + 4,5 (locked-out)
100 if kno != 0 { ok = 0 }
101 if st[1] != WL_ADMITTED { ok = 0 }
102 if st[2] != WL_DENIED { ok = 0 }
103 if st[3] != WL_ADMITTED { ok = 0 }
104 if st[9] != WL_UNKNOWN { ok = 0 } // I1: ghost admit ignored
105 if st[4] != WL_DENIED { ok = 0 } // I2: locked knock closed out
106 if st[6] != WL_ADMITTED { ok = 0 } // ADMIT_ALL
107
108 // neg-control: SAME timeline but event 8 (LOCK) replaced by UNLOCK -> id4 knocks
109 // in OPEN mode and the trailing ADMIT_ALL lets it IN (ADMITTED). So the LOCK is
110 // the ONLY thing that kept id4 out: locked -> DENIED, open -> ADMITTED. The rule
111 // is MATERIAL iff id4's fate differs between the two runs (rule-sensitivity).
112 let st2: *i64 = sys_mmap(8 * 16) as *i64
113 evt[7] = 6 // was LOCK(5), now UNLOCK(6) = no lock
114 wl_run(MAXID, evt, eid, n, st2)
115 if st2[4] != WL_ADMITTED { ok = 0 } // open-mode + ADMIT_ALL -> id4 gets in
116 if st2[4] == st[4] { ok = 0 } // lock MATERIALLY changed id4's fate (2 vs 3)
117
118 ww(1, "ROOMWAITGATE admitted=" as *u8); wwn(1, adm); ww(1, " denied=" as *u8); wwn(1, den)
119 ww(1, " knocking=" as *u8); wwn(1, kno); ww(1, " ghost9=" as *u8); wwn(1, st[9])
120 ww(1, " locked_knock4=" as *u8); wwn(1, st[4]); ww(1, " open_knock4=" as *u8); wwn(1, st2[4])
121 if ok == 1 { ww(1, " verdict=GREEN\n" as *u8) } else { ww(1, " verdict=RED\n" as *u8) }
122
123 let lf: i64 = sys_openat_append(WL_LOG, 420)
124 if lf >= 0 {
125 ww(lf, "ROOMWAITGATE admitted=" as *u8); wwn(lf, adm); ww(lf, " denied=" as *u8); wwn(lf, den)
126 ww(lf, " knocking=" as *u8); wwn(lf, kno); ww(lf, " ghost9=" as *u8); wwn(lf, st[9])
127 ww(lf, " locked_knock4=" as *u8); wwn(lf, st[4]); ww(lf, " open_knock4=" as *u8); wwn(lf, st2[4])
128 if ok == 1 { ww(lf, " verdict=GREEN\n" as *u8) } else { ww(lf, " verdict=RED\n" as *u8) }
129 sys_close(lf)
130 }
131 if ok == 1 { sys_exit(0) } else { sys_exit(1) }
132 return 0
133}