nx_iot_anchor_test.nx source
↩ module page · 164 lines · 8808 B
1// nx_iot_anchor_test.nx -- gate for the stable device-identity anchor.
2//
3// Proves the duplicate-on-repair failure mode is closed BY CONSTRUCTION
4// and measures the phantom devices a naive (incumbent-app) controller
5// would have accrued over the same pairing events.
6//
7// Grounded in the live fleet: device A's hardware id is the REAL BSSID
8// of the operator's TP-Link Kasa HS210 switch found in pairing mode on
9// 2026-06-18 (SSID TP-LINK_HS210_C209, BSSID d8:0d:17:a1:c2:09).
10//
11// Coverage:
12// - vendor + adopt-verdict sealed-enum validity gates
13// - init writes a coherent registry
14// - adopt new device -> NEW + fresh logical id
15// - RE-ADOPT same device (the blink/re-pair) -> READOPTED, SAME
16// logical id, NO new row, volatile fields refreshed, write-once
17// fields (logical_id, first_seen) preserved
18// - a second device gets its own logical id
19// - MEASURED EXCEED: duplicates_prevented == naive_adopts - count
20// - friendly name set + survives, miss -> NOT_FOUND
21// - soft-delete is additive (row kept, count unchanged, current drops)
22// - re-adopt revives a soft-deleted device on the same anchor
23// - negative controls: bad hwid_n / oversize hwid_n / invalid vendor
24// -> BAD_ARG with NO state change
25// - capacity guard: 3rd distinct device at cap=2 -> FULL; re-adopt at
26// cap still succeeds
27// - lookup misses return -1
28//
29// expect_exit: 0
30//
31// license_tier: ORIGINAL
32
33import "nx_syscalls_x86_64.nx"
34import "nx_iot_anchor.nx"
35
36func main() -> i64 {
37 // ---- vendor validity gate --------------------------------------
38 if nx_iot_vendor_is_valid(NX_IOT_VENDOR_UNKNOWN) != 1 { return 1 }
39 if nx_iot_vendor_is_valid(NX_IOT_VENDOR_KASA) != 1 { return 2 }
40 if nx_iot_vendor_is_valid(NX_IOT_VENDOR_N) != 0 { return 3 }
41 if nx_iot_vendor_is_valid(-1) != 0 { return 4 }
42 if nx_iot_vendor_is_valid(99) != 0 { return 5 }
43
44 // ---- adopt-verdict validity gate -------------------------------
45 if nx_iot_anchor_verdict_is_valid(NX_IOT_ANCHOR_NEW) != 1 { return 6 }
46 if nx_iot_anchor_verdict_is_valid(NX_IOT_ANCHOR_READOPTED) != 1 { return 7 }
47 if nx_iot_anchor_verdict_is_valid(NX_IOT_ANCHOR_NOT_FOUND) != 1 { return 8 }
48 if nx_iot_anchor_verdict_is_valid(NX_IOT_ANCHOR_N) != 0 { return 9 }
49 if nx_iot_anchor_verdict_is_valid(-1) != 0 { return 10 }
50
51 // ---- alloc + init ----------------------------------------------
52 let reg: *IotAnchorReg = sys_mmap(64) as *IotAnchorReg
53 let metas: *IotDeviceMeta = sys_mmap(512) as *IotDeviceMeta
54 let blob: *u8 = sys_mmap(512)
55 let qv: *i64 = sys_mmap(8) as *i64
56
57 if nx_iot_anchor_init(reg, 8) != 0 { return 20 }
58 if reg.count != 0 { return 21 }
59 if reg.cap != 8 { return 22 }
60 if reg.next_logical_id != 1 { return 23 }
61 if reg.naive_adopts != 0 { return 24 }
62
63 // ---- adopt A (the live Kasa HS210) -> NEW, logical 1 -----------
64 let la: i64 = nx_iot_anchor_adopt(reg, metas, blob, "d8:0d:17:a1:c2:09", 17, NX_IOT_VENDOR_KASA, 0xC0A80878, 1000, qv)
65 if la != 1 { return 30 }
66 if qv[0] != NX_IOT_ANCHOR_NEW { return 31 }
67 if nx_iot_anchor_count(reg) != 1 { return 32 }
68 if nx_iot_anchor_naive_adopts(reg) != 1 { return 33 }
69 if nx_iot_anchor_logical_adopt_count(reg, metas, 1) != 1 { return 34 }
70 if nx_iot_anchor_logical_is_current(reg, metas, 1) != 1 { return 35 }
71 if nx_iot_anchor_logical_vendor(reg, metas, 1) != NX_IOT_VENDOR_KASA { return 36 }
72 if nx_iot_anchor_logical_ip(reg, metas, 1) != 0xC0A80878 { return 37 }
73
74 let sa: i64 = nx_iot_anchor_slot_by_logical(reg, metas, 1)
75 if sa != 0 { return 38 }
76 let ma: *IotDeviceMeta = nx_iot_anchor_meta_ptr(metas, sa)
77 if ma.first_seen != 1000 { return 39 }
78
79 // ---- RE-ADOPT A (the blink/re-pair) -> SAME logical 1, NO dup --
80 let la2: i64 = nx_iot_anchor_adopt(reg, metas, blob, "d8:0d:17:a1:c2:09", 17, NX_IOT_VENDOR_KASA, 0xC0A8087E, 2000, qv)
81 if la2 != 1 { return 40 }
82 if qv[0] != NX_IOT_ANCHOR_READOPTED { return 41 }
83 if nx_iot_anchor_count(reg) != 1 { return 42 }
84 if nx_iot_anchor_naive_adopts(reg) != 2 { return 43 }
85 if nx_iot_anchor_logical_adopt_count(reg, metas, 1) != 2 { return 44 }
86 if nx_iot_anchor_logical_ip(reg, metas, 1) != 0xC0A8087E { return 45 }
87 if ma.first_seen != 1000 { return 46 }
88 if ma.last_seen != 2000 { return 47 }
89
90 // ---- adopt B -> NEW, logical 2 ---------------------------------
91 let lb: i64 = nx_iot_anchor_adopt(reg, metas, blob, "d8:0d:17:b2:33:44", 17, NX_IOT_VENDOR_TUYA, 0xC0A8089F, 3000, qv)
92 if lb != 2 { return 50 }
93 if qv[0] != NX_IOT_ANCHOR_NEW { return 51 }
94 if nx_iot_anchor_count(reg) != 2 { return 52 }
95 if nx_iot_anchor_naive_adopts(reg) != 3 { return 53 }
96
97 // ---- RE-ADOPT A a third time -> still logical 1, count still 2 -
98 let la3: i64 = nx_iot_anchor_adopt(reg, metas, blob, "d8:0d:17:a1:c2:09", 17, NX_IOT_VENDOR_KASA, 0xC0A80878, 4000, qv)
99 if la3 != 1 { return 60 }
100 if qv[0] != NX_IOT_ANCHOR_READOPTED { return 61 }
101 if nx_iot_anchor_count(reg) != 2 { return 62 }
102 if nx_iot_anchor_logical_adopt_count(reg, metas, 1) != 3 { return 63 }
103
104 // ---- MEASURED EXCEED ------------------------------------------
105 // 4 pairing events (A, A, B, A): a dedup-free app = 4 device rows;
106 // the anchor keeps 2. duplicates_prevented = 4 - 2 = 2.
107 if nx_iot_anchor_naive_adopts(reg) != 4 { return 70 }
108 if nx_iot_anchor_count(reg) != 2 { return 71 }
109 if nx_iot_anchor_duplicates_prevented(reg) != 2 { return 72 }
110
111 // ---- friendly name survives re-pairs ---------------------------
112 if nx_iot_anchor_set_name(reg, metas, blob, 1, "Kitchen Switch", 14, qv) != 0 { return 80 }
113 if qv[0] != NX_IOT_ANCHOR_UPDATED { return 81 }
114 let mn: *IotDeviceMeta = nx_iot_anchor_meta_ptr(metas, 0)
115 if mn.name_len != 14 { return 82 }
116 let nbase: i64 = nx_iot_anchor_name_base(0)
117 if blob[nbase] != 0x4B { return 83 } // 'K'
118 if blob[nbase + 1] != 0x69 { return 84 } // 'i'
119 if nx_iot_anchor_set_name(reg, metas, blob, 999, "X", 1, qv) != -1 { return 85 }
120 if qv[0] != NX_IOT_ANCHOR_NOT_FOUND { return 86 }
121
122 // ---- soft-delete is additive (history sacred, CLAUDE.md #13) ---
123 if nx_iot_anchor_mark_unreachable(reg, metas, 2, qv) != 0 { return 90 }
124 if qv[0] != NX_IOT_ANCHOR_UPDATED { return 91 }
125 if nx_iot_anchor_logical_is_current(reg, metas, 2) != 0 { return 92 }
126 if nx_iot_anchor_count(reg) != 2 { return 93 }
127 if nx_iot_anchor_count_current(reg, metas) != 1 { return 94 }
128 // re-adopt B -> revives on the SAME anchor
129 let lb2: i64 = nx_iot_anchor_adopt(reg, metas, blob, "d8:0d:17:b2:33:44", 17, NX_IOT_VENDOR_TUYA, 0xC0A8089F, 5000, qv)
130 if lb2 != 2 { return 95 }
131 if qv[0] != NX_IOT_ANCHOR_READOPTED { return 96 }
132 if nx_iot_anchor_logical_is_current(reg, metas, 2) != 1 { return 97 }
133 if nx_iot_anchor_count_current(reg, metas) != 2 { return 98 }
134
135 // ---- negative controls: bad args -> BAD_ARG, no state change ---
136 let cbefore: i64 = nx_iot_anchor_count(reg)
137 if nx_iot_anchor_adopt(reg, metas, blob, "d8:0d:17:a1:c2:09", 0, NX_IOT_VENDOR_KASA, 0, 6000, qv) != -1 { return 100 }
138 if qv[0] != NX_IOT_ANCHOR_BAD_ARG { return 101 }
139 if nx_iot_anchor_adopt(reg, metas, blob, "d8:0d:17:a1:c2:09", 33, NX_IOT_VENDOR_KASA, 0, 6000, qv) != -1 { return 102 }
140 if qv[0] != NX_IOT_ANCHOR_BAD_ARG { return 103 }
141 if nx_iot_anchor_adopt(reg, metas, blob, "d8:0d:17:a1:c2:09", 17, 99, 0, 6000, qv) != -1 { return 104 }
142 if qv[0] != NX_IOT_ANCHOR_BAD_ARG { return 105 }
143 if nx_iot_anchor_count(reg) != cbefore { return 106 }
144
145 // ---- capacity guard (separate small registry) ------------------
146 let reg2: *IotAnchorReg = sys_mmap(64) as *IotAnchorReg
147 let metas2: *IotDeviceMeta = sys_mmap(128) as *IotDeviceMeta
148 let blob2: *u8 = sys_mmap(128)
149 if nx_iot_anchor_init(reg2, 2) != 0 { return 110 }
150 if nx_iot_anchor_adopt(reg2, metas2, blob2, "aa:aa:aa:aa:aa:01", 17, NX_IOT_VENDOR_WIZ, 0, 1, qv) != 1 { return 111 }
151 if nx_iot_anchor_adopt(reg2, metas2, blob2, "aa:aa:aa:aa:aa:02", 17, NX_IOT_VENDOR_WIZ, 0, 1, qv) != 2 { return 112 }
152 if nx_iot_anchor_adopt(reg2, metas2, blob2, "aa:aa:aa:aa:aa:03", 17, NX_IOT_VENDOR_WIZ, 0, 1, qv) != -1 { return 113 }
153 if qv[0] != NX_IOT_ANCHOR_FULL { return 114 }
154 if nx_iot_anchor_count(reg2) != 2 { return 115 }
155 let r2: i64 = nx_iot_anchor_adopt(reg2, metas2, blob2, "aa:aa:aa:aa:aa:01", 17, NX_IOT_VENDOR_WIZ, 0, 2, qv)
156 if r2 != 1 { return 116 }
157 if qv[0] != NX_IOT_ANCHOR_READOPTED { return 117 }
158
159 // ---- lookup misses return -1 -----------------------------------
160 if nx_iot_anchor_slot_by_logical(reg, metas, 12345) != -1 { return 120 }
161 if nx_iot_anchor_find(reg, blob, "ff:ff:ff:ff:ff:ff", 17) != -1 { return 121 }
162
163 return 0
164}