code wiki / _hdl_build / nx_connect_presence.nx
nx_connect_presence.nx source
↩ module page · 255 lines · 10035 B
1// nx_connect_presence.nx -- CONNECT: typing indicator + online presence + scheduled/silent send.
2// Closes two MSG cells of nx_connect_func_census (typing+presence; scheduled/silent send).
3// BY CONSTRUCTION properties:
4// - the typing signal is a {conv,user,expiry} triple ONLY -- no draft-text field exists in the
5// schema, and it EXPIRES (ephemeral): presence never becomes a stale lie. NEG-CONTROL: a sticky
6// no-TTL incumbent model still claims "typing" an hour later; ours has expired.
7// - last-seen privacy is the USER's setting: a coarse-mode profile renders only a "recently"
8// bucket, never the exact timestamp (data minimization at render time).
9// - scheduled send delivers exactly AT/after the due tick, never early; SILENT send delivers with
10// ZERO notification events (Telegram-class silent send); the delivery tick is IDEMPOTENT
11// (rule 10: a re-run tick cannot double-send).
12// Times are passed in (deterministic, no clock). 100% sovereign. license_tier: ORIGINAL expect_exit: 0
13import "nx_syscalls.nx"
14const PR_MAGIC_4600: i64 = 4600
15const PR_MAGIC_2000: i64 = 2000
16const PR_MAGIC_1999: i64 = 1999
17const PR_MAGIC_2100: i64 = 2100
18
19const PR_MAX: i64 = 16
20const TY_MAX: i64 = 32
21const SC_MAX: i64 = 16
22const TY_TTL: i64 = 5
23
24const CX_PRU: i64 = 0
25const CX_PRST: i64 = 1
26const CX_PRLAST: i64 = 2
27const CX_PRCOARSE: i64 = 3
28const CX_NPR: i64 = 4
29const CX_TYC: i64 = 5
30const CX_TYU: i64 = 6
31const CX_TYX: i64 = 7
32const CX_NTY: i64 = 8
33const CX_SCDUE: i64 = 9
34const CX_SCSIL: i64 = 10
35const CX_SCSENT: i64 = 11
36const CX_NSC: i64 = 12
37const CX_DELIV: i64 = 13
38const CX_NOTIF: i64 = 14
39
40func sw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
41func sn(v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;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(1,bb,k); return 0 }
42func tcheck(pass: i64, label: *u8, fails: *i64) -> i64 {
43 sw(" " as *u8); sw(label); sw(": " as *u8)
44 if pass==1 { sw("PASS\n" as *u8) } else { sw("FAIL\n" as *u8); fails[0]=fails[0]+1 }
45 return 0
46}
47func cxp(ctx: *i64, i: i64) -> *i64 { return ctx[i] as *i64 }
48
49func pr_idx(ctx: *i64, user: i64) -> i64 {
50 let pu: *i64 = cxp(ctx, CX_PRU)
51 let np: *i64 = cxp(ctx, CX_NPR)
52 var i: i64=0
53 while i<np[0] { if pu[i]==user { return i } i=i+1 }
54 return 0-1
55}
56func pr_set(ctx: *i64, user: i64, state: i64, now: i64) -> i64 {
57 var i: i64 = pr_idx(ctx, user)
58 let pu: *i64 = cxp(ctx, CX_PRU)
59 let ps: *i64 = cxp(ctx, CX_PRST)
60 let pl: *i64 = cxp(ctx, CX_PRLAST)
61 let np: *i64 = cxp(ctx, CX_NPR)
62 if i<0 { i=np[0]; pu[i]=user; np[0]=i+1 }
63 ps[i]=state
64 pl[i]=now
65 return i
66}
67// viewer render: 0 offline-exact 1 online 2 away 3 offline-coarse("recently"). -1 unknown user.
68func pr_view(ctx: *i64, target: i64, now: i64) -> i64 {
69 let i: i64 = pr_idx(ctx, target)
70 if i<0 { return 0-1 }
71 let ps: *i64 = cxp(ctx, CX_PRST)
72 let pc: *i64 = cxp(ctx, CX_PRCOARSE)
73 if ps[i]==1 { return 1 }
74 if ps[i]==2 { return 2 }
75 if pc[i]==1 { return 3 }
76 return 0
77}
78// exact last_seen ONLY for a non-coarse profile; coarse -> -1 (the exact number never leaves)
79func pr_last_seen(ctx: *i64, target: i64) -> i64 {
80 let i: i64 = pr_idx(ctx, target)
81 if i<0 { return 0-1 }
82 let pc: *i64 = cxp(ctx, CX_PRCOARSE)
83 let pl: *i64 = cxp(ctx, CX_PRLAST)
84 if pc[i]==1 { return 0-1 }
85 return pl[i]
86}
87func ty_set(ctx: *i64, conv: i64, user: i64, now: i64) -> i64 {
88 let tc: *i64 = cxp(ctx, CX_TYC)
89 let tu: *i64 = cxp(ctx, CX_TYU)
90 let tx: *i64 = cxp(ctx, CX_TYX)
91 let nt: *i64 = cxp(ctx, CX_NTY)
92 var i: i64=0
93 while i<nt[0] {
94 if tc[i]==conv { if tu[i]==user { tx[i]=now+TY_TTL; return i } }
95 i=i+1
96 }
97 let k: i64=nt[0]
98 tc[k]=conv; tu[k]=user; tx[k]=now+TY_TTL
99 nt[0]=k+1
100 return k
101}
102// ephemeral: active iff now < expiry. the schema has NO draft-text field at all.
103func ty_active(ctx: *i64, conv: i64, user: i64, now: i64) -> i64 {
104 let tc: *i64 = cxp(ctx, CX_TYC)
105 let tu: *i64 = cxp(ctx, CX_TYU)
106 let tx: *i64 = cxp(ctx, CX_TYX)
107 let nt: *i64 = cxp(ctx, CX_NTY)
108 var i: i64=0
109 while i<nt[0] {
110 if tc[i]==conv { if tu[i]==user { if now<tx[i] { return 1 } return 0 } }
111 i=i+1
112 }
113 return 0
114}
115// NEG-CONTROL incumbent: sticky typing flag with NO expiry -- stale presence forever
116func ty_sticky_active(set_at: i64, now: i64) -> i64 {
117 if now>=set_at { return 1 }
118 return 0
119}
120// schedule a message; delivery via sc_tick. silent=1 -> no notification event on delivery.
121func sc_add(ctx: *i64, due: i64, silent: i64) -> i64 {
122 let sd: *i64 = cxp(ctx, CX_SCDUE)
123 let ss: *i64 = cxp(ctx, CX_SCSIL)
124 let st: *i64 = cxp(ctx, CX_SCSENT)
125 let ns: *i64 = cxp(ctx, CX_NSC)
126 let k: i64=ns[0]
127 sd[k]=due; ss[k]=silent; st[k]=0
128 ns[0]=k+1
129 return k
130}
131// IDEMPOTENT delivery tick: due & unsent -> deliver once; notify unless silent.
132func sc_tick(ctx: *i64, now: i64) -> i64 {
133 let sd: *i64 = cxp(ctx, CX_SCDUE)
134 let ss: *i64 = cxp(ctx, CX_SCSIL)
135 let st: *i64 = cxp(ctx, CX_SCSENT)
136 let ns: *i64 = cxp(ctx, CX_NSC)
137 let dl: *i64 = cxp(ctx, CX_DELIV)
138 let nf: *i64 = cxp(ctx, CX_NOTIF)
139 var sent_now: i64=0
140 var i: i64=0
141 while i<ns[0] {
142 if st[i]==0 {
143 if now>=sd[i] {
144 st[i]=1
145 dl[0]=dl[0]+1
146 if ss[i]==0 { nf[0]=nf[0]+1 }
147 sent_now=sent_now+1
148 }
149 }
150 i=i+1
151 }
152 return sent_now
153}
154
155func main() -> i64 {
156 let fails: *i64 = sys_mmap(16) as *i64
157 fails[0]=0
158 sw("=== nx_connect_presence -- typing + presence + scheduled/silent send ===\n" as *u8)
159
160 let ctx: *i64 = sys_mmap(16*8) as *i64
161 let pr_user: *i64 = sys_mmap(PR_MAX*8) as *i64
162 let pr_state: *i64 = sys_mmap(PR_MAX*8) as *i64
163 let pr_last: *i64 = sys_mmap(PR_MAX*8) as *i64
164 let pr_coarse: *i64 = sys_mmap(PR_MAX*8) as *i64
165 let npr: *i64 = sys_mmap(8) as *i64
166 npr[0]=0
167 let ty_conv: *i64 = sys_mmap(TY_MAX*8) as *i64
168 let ty_user: *i64 = sys_mmap(TY_MAX*8) as *i64
169 let ty_exp: *i64 = sys_mmap(TY_MAX*8) as *i64
170 let nty: *i64 = sys_mmap(8) as *i64
171 nty[0]=0
172 let sc_due: *i64 = sys_mmap(SC_MAX*8) as *i64
173 let sc_sil: *i64 = sys_mmap(SC_MAX*8) as *i64
174 let sc_sent: *i64 = sys_mmap(SC_MAX*8) as *i64
175 let nsc: *i64 = sys_mmap(8) as *i64
176 nsc[0]=0
177 let deliv: *i64 = sys_mmap(8) as *i64
178 deliv[0]=0
179 let notif: *i64 = sys_mmap(8) as *i64
180 notif[0]=0
181 ctx[CX_PRU]=pr_user as i64; ctx[CX_PRST]=pr_state as i64; ctx[CX_PRLAST]=pr_last as i64
182 ctx[CX_PRCOARSE]=pr_coarse as i64; ctx[CX_NPR]=npr as i64
183 ctx[CX_TYC]=ty_conv as i64; ctx[CX_TYU]=ty_user as i64; ctx[CX_TYX]=ty_exp as i64
184 ctx[CX_NTY]=nty as i64
185 ctx[CX_SCDUE]=sc_due as i64; ctx[CX_SCSIL]=sc_sil as i64; ctx[CX_SCSENT]=sc_sent as i64
186 ctx[CX_NSC]=nsc as i64
187 ctx[CX_DELIV]=deliv as i64
188 ctx[CX_NOTIF]=notif as i64
189
190 // T1: presence transitions online -> away -> offline
191 pr_set(ctx, 1, 1, 100)
192 let v1a: i64 = pr_view(ctx, 1, 100)
193 pr_set(ctx, 1, 2, 150)
194 let v1b: i64 = pr_view(ctx, 1, 150)
195 pr_set(ctx, 1, 0, 200)
196 let v1c: i64 = pr_view(ctx, 1, 200)
197 var t1: i64=0
198 if v1a==1 { if v1b==2 { if v1c==0 { t1=1 } } }
199 tcheck(t1, "T1 presence transitions online/away/offline render correctly" as *u8, fails)
200
201 // T2: last-seen privacy -- coarse profile renders bucket only, exact timestamp never leaves
202 pr_set(ctx, 2, 0, 555)
203 let i2: i64 = pr_idx(ctx, 2)
204 pr_coarse[i2]=1
205 let v2: i64 = pr_view(ctx, 2, 600)
206 let ls2: i64 = pr_last_seen(ctx, 2)
207 let ls1: i64 = pr_last_seen(ctx, 1)
208 var t2: i64=0
209 if v2==3 { if ls2==(0-1) { if ls1==200 { t2=1 } } }
210 tcheck(t2, "T2 last-seen privacy: coarse profile leaks NO exact timestamp; exact mode does" as *u8, fails)
211
212 // T3: typing is EPHEMERAL -- active now, expired after TTL
213 ty_set(ctx, 40, 1, 1000)
214 let a3: i64 = ty_active(ctx, 40, 1, 1002)
215 let b3: i64 = ty_active(ctx, 40, 1, 1006)
216 var t3: i64=0
217 if a3==1 { if b3==0 { t3=1 } }
218 tcheck(t3, "T3 typing indicator ephemeral: active in-window, expired after TTL" as *u8, fails)
219
220 // T4: NEG-CONTROL sticky incumbent still 'typing' an hour later; ours expired
221 let s4: i64 = ty_sticky_active(1000, PR_MAGIC_4600)
222 let o4: i64 = ty_active(ctx, 40, 1, PR_MAGIC_4600)
223 var t4: i64=0
224 if s4==1 { if o4==0 { t4=1 } }
225 tcheck(t4, "T4 NEG-CONTROL sticky no-TTL model lies an hour later; ours expired" as *u8, fails)
226
227 // T5: scheduled send -- never early, delivered at due
228 let m5: i64 = sc_add(ctx, PR_MAGIC_2000, 0)
229 let e5: i64 = sc_tick(ctx, PR_MAGIC_1999)
230 let d5: i64 = sc_tick(ctx, PR_MAGIC_2000)
231 var t5: i64=0
232 if e5==0 { if d5==1 { if sc_sent[m5]==1 { t5=1 } } }
233 tcheck(t5, "T5 scheduled send: not delivered early, delivered at due tick" as *u8, fails)
234
235 // T6: silent send delivers with ZERO notification events; normal send emitted 1
236 let n_before: i64 = notif[0]
237 let m6: i64 = sc_add(ctx, PR_MAGIC_2100, 1)
238 sc_tick(ctx, PR_MAGIC_2100)
239 var t6: i64=0
240 if sc_sent[m6]==1 { if notif[0]==n_before { t6=1 } }
241 tcheck(t6, "T6 silent send: delivered with zero notification events" as *u8, fails)
242
243 // T7: IDEMPOTENT tick -- re-running the same tick cannot double-send (rule 10)
244 let dv_before: i64 = deliv[0]
245 let r7: i64 = sc_tick(ctx, PR_MAGIC_2100)
246 var t7: i64=0
247 if r7==0 { if deliv[0]==dv_before { t7=1 } }
248 tcheck(t7, "T7 delivery tick idempotent: re-run sends nothing twice" as *u8, fails)
249
250 sw(" fails=" as *u8); sn(fails[0]); sw("\n" as *u8)
251 if fails[0]==0 { sw("VERDICT: GREEN (presence/typing ephemeral by construction; scheduled + silent send idempotent)\n" as *u8); sys_exit(0) }
252 sw("VERDICT: RED\n" as *u8)
253 sys_exit(1)
254 return 1
255}