nx_iot_scene_sync_test.nx source
↩ module page · 119 lines · 6665 B
1// nx_iot_scene_sync_test.nx -- gate for the lights-stay-in-sync organ.
2//
3// Proves the operator's "repeatable self-fixing" sync as PURE LOGIC:
4// - sealed-enum validity
5// - init + set_scene establishes a single source of truth (epoch bumps)
6// - new devices start OUT of sync; resync_all converges the whole fleet
7// - all_in_sync flips correctly; count_desynced is exact
8// - DROP+HEAL: a device marked desynced is out of sync, then resync pulls
9// it back -- and REPEATING the drop+heal re-fixes it every time
10// - MEASURED syncs_restored / desyncs_seen grow with each cycle
11// - a SCENE CHANGE knocks the whole fleet out of sync (new epoch) until
12// re-applied -- the room re-syncs as one
13// - idempotent add (#10); not-found / bad-arg guards
14//
15// expect_exit: 0
16//
17// license_tier: ORIGINAL
18
19import "nx_syscalls_x86_64.nx"
20import "nx_iot_scene_sync.nx"
21
22func main() -> i64 {
23 // ---- sealed-enum validity --------------------------------------
24 if nx_iot_sync_verdict_is_valid(NX_IOT_SYNC_OK) != 1 { return 1 }
25 if nx_iot_sync_verdict_is_valid(NX_IOT_SYNC_NEEDS_RESYNC) != 1 { return 2 }
26 if nx_iot_sync_verdict_is_valid(NX_IOT_SYNC_N) != 0 { return 3 }
27 if nx_iot_sync_verdict_is_valid(-1) != 0 { return 4 }
28
29 let reg: *IotSceneReg = sys_mmap(128) as *IotSceneReg
30 let devs: *i64 = sys_mmap(256) as *i64 // 16 device slots * 2 i64
31
32 // ---- init ------------------------------------------------------
33 if nx_iot_scene_init(reg, 8) != NX_IOT_SYNC_OK { return 10 }
34 if nx_iot_scene_epoch(reg) != 0 { return 11 }
35 if nx_iot_scene_count(reg) != 0 { return 12 }
36 if nx_iot_scene_all_in_sync(reg, devs) != 1 { return 13 } // empty = vacuously synced
37 if nx_iot_scene_init(0 as *IotSceneReg, 8) != NX_IOT_SYNC_BAD_ARG { return 14 }
38
39 // ---- set the desired scene (warm white, 70%) -> epoch 1 --------
40 if nx_iot_scene_set(reg, 1, 70, 30, 80, 2700) != NX_IOT_SYNC_OK { return 20 }
41 if nx_iot_scene_epoch(reg) != 1 { return 21 }
42 if nx_iot_scene_get_brightness(reg) != 70 { return 22 }
43 if nx_iot_scene_get_on(reg) != 1 { return 23 }
44
45 // ---- add 3 lights -> all OUT of sync ---------------------------
46 if nx_iot_scene_add_device(reg, devs, 101) != NX_IOT_SYNC_OK { return 30 }
47 if nx_iot_scene_add_device(reg, devs, 102) != NX_IOT_SYNC_OK { return 31 }
48 if nx_iot_scene_add_device(reg, devs, 103) != NX_IOT_SYNC_OK { return 32 }
49 if nx_iot_scene_count(reg) != 3 { return 33 }
50 if nx_iot_scene_add_device(reg, devs, 101) != NX_IOT_SYNC_OK { return 34 } // idempotent
51 if nx_iot_scene_count(reg) != 3 { return 35 }
52 if nx_iot_scene_all_in_sync(reg, devs) != 0 { return 36 }
53 if nx_iot_scene_count_desynced(reg, devs) != 3 { return 37 }
54 if nx_iot_scene_needs_resync(reg, devs, 101) != 1 { return 38 }
55 if nx_iot_scene_in_sync(reg, devs, 101) != 0 { return 39 }
56
57 // ---- converge the whole room -> all in sync --------------------
58 if nx_iot_scene_resync_all(reg, devs) != 3 { return 40 } // 3 restored
59 if nx_iot_scene_all_in_sync(reg, devs) != 1 { return 41 }
60 if nx_iot_scene_count_desynced(reg, devs) != 0 { return 42 }
61 if nx_iot_scene_syncs_restored(reg) != 3 { return 43 }
62 if nx_iot_scene_in_sync(reg, devs, 102) != 1 { return 44 }
63
64 // ---- THE SELF-FIX: a light drops/blinks + heals -> re-synced ---
65 // device 102 dropped WiFi, re-paired (watchdog+anchor), came back at its
66 // DEFAULT state -> out of sync. The loop pulls it back to the scene.
67 if nx_iot_scene_mark_desynced(reg, devs, 102) != NX_IOT_SYNC_OK { return 50 }
68 if nx_iot_scene_all_in_sync(reg, devs) != 0 { return 51 }
69 if nx_iot_scene_count_desynced(reg, devs) != 1 { return 52 }
70 if nx_iot_scene_needs_resync(reg, devs, 102) != 1 { return 53 }
71 if nx_iot_scene_desyncs_seen(reg) != 1 { return 54 }
72 let r1: i64 = nx_iot_scene_resync(reg, devs, 102)
73 if r1 != 1 { return 55 } // a re-sync happened
74 if nx_iot_scene_all_in_sync(reg, devs) != 1 { return 56 } // back in sync
75 if nx_iot_scene_syncs_restored(reg) != 4 { return 57 }
76 if nx_iot_scene_resync(reg, devs, 102) != 0 { return 58 } // already in sync -> no-op
77
78 // ---- REPEATABLE: 102 blinks again + again, fixed each time -----
79 nx_iot_scene_mark_desynced(reg, devs, 102)
80 nx_iot_scene_resync(reg, devs, 102)
81 nx_iot_scene_mark_desynced(reg, devs, 102)
82 nx_iot_scene_resync(reg, devs, 102)
83 if nx_iot_scene_all_in_sync(reg, devs) != 1 { return 60 }
84 if nx_iot_scene_desyncs_seen(reg) != 3 { return 61 } // 3 blinks total
85 if nx_iot_scene_syncs_restored(reg) != 6 { return 62 } // 3 + 3 auto re-syncs
86 // a different light drifts too -> still converges
87 nx_iot_scene_mark_desynced(reg, devs, 101)
88 nx_iot_scene_mark_desynced(reg, devs, 103)
89 if nx_iot_scene_count_desynced(reg, devs) != 2 { return 63 }
90 if nx_iot_scene_resync_all(reg, devs) != 2 { return 64 }
91 if nx_iot_scene_all_in_sync(reg, devs) != 1 { return 65 }
92 if nx_iot_scene_syncs_restored(reg) != 8 { return 66 }
93
94 // ---- SCENE CHANGE: new epoch knocks the whole room out of sync -
95 // operator picks a new colour -> every light must re-apply as one.
96 if nx_iot_scene_set(reg, 1, 40, 200, 100, 4000) != NX_IOT_SYNC_OK { return 70 }
97 if nx_iot_scene_epoch(reg) != 2 { return 71 }
98 if nx_iot_scene_get_brightness(reg) != 40 { return 72 }
99 if nx_iot_scene_all_in_sync(reg, devs) != 0 { return 73 } // all behind the new epoch
100 if nx_iot_scene_count_desynced(reg, devs) != 3 { return 74 }
101 if nx_iot_scene_resync_all(reg, devs) != 3 { return 75 } // re-apply to all (atomic via clock master)
102 if nx_iot_scene_all_in_sync(reg, devs) != 1 { return 76 }
103 if nx_iot_scene_syncs_restored(reg) != 11 { return 77 }
104
105 // ---- guards ----------------------------------------------------
106 if nx_iot_scene_mark_applied(reg, devs, 999) != NX_IOT_SYNC_NOT_FOUND { return 80 }
107 if nx_iot_scene_mark_desynced(reg, devs, 999) != NX_IOT_SYNC_NOT_FOUND { return 81 }
108 if nx_iot_scene_resync(reg, devs, 999) != -1 { return 82 }
109 if nx_iot_scene_in_sync(reg, devs, 999) != 0 { return 83 }
110 // capacity guard (small registry)
111 let reg2: *IotSceneReg = sys_mmap(128) as *IotSceneReg
112 let devs2: *i64 = sys_mmap(64) as *i64
113 if nx_iot_scene_init(reg2, 2) != NX_IOT_SYNC_OK { return 84 }
114 if nx_iot_scene_add_device(reg2, devs2, 1) != NX_IOT_SYNC_OK { return 85 }
115 if nx_iot_scene_add_device(reg2, devs2, 2) != NX_IOT_SYNC_OK { return 86 }
116 if nx_iot_scene_add_device(reg2, devs2, 3) != NX_IOT_SYNC_FULL { return 87 }
117
118 return 0
119}