code wiki / (root) / nx_iot_provision_softap_test.nx

nx_iot_provision_softap_test.nx source

↩ module page · 240 lines · 12846 B

1// nx_iot_provision_softap_test.nx -- gate for the auto-pair state machine. 2// 3// Proves the operator's "no more manual re-pair" outcome as PURE LOGIC, 4// off the LAN, plus the never-brick guarantee (CLAUDE.md #26) mechanically: 5// 6// - sealed-enum validity (state / action / event / fail) 7// - NEVER-BRICK: every action in the alphabet is brick-safe and writes 8// no firmware; the firmware classifier is FAIL-SAFE (an out-of-range 9// / future action defaults to "writes firmware" = RED) 10// - init writes a coherent session; default + override + null guard 11// - pairing-SSID filter routes known vendors, rejects unknown APs 12// - HAPPY PATH end-to-end: SCAN -> JOIN -> PUSH_CREDS -> REJOIN -> VERIFY 13// -> ANCHOR -> DONE, asserting action + state + brick-safety each step, 14// landing a stable logical id with NO manual step 15// - terminal states are sticky + idempotent (CLAUDE.md #10) 16// - every FAILURE path: no-AP, unknown-vendor, join/push/rejoin/verify 17// retries-exhausted, anchor-fail -- each with the right sealed reason 18// - bounded retry RECOVERS (transient join failure then success) 19// - defensive: malformed event is a no-op; null session does not crash 20// 21// Grounded in the live fleet: the pairing SSID is the operator's REAL 22// device, TP-LINK_HS210_C209 (the Kasa HS210 found blinking 2026-06-18). 23// 24// expect_exit: 0 25// 26// license_tier: ORIGINAL 27 28import "nx_syscalls_x86_64.nx" 29import "nx_iot_provision_softap.nx" 30 31func main() -> i64 { 32 // ---- sealed-enum validity -------------------------------------- 33 if nx_iot_prov_state_is_valid(PROV_ST_IDLE) != 1 { return 1 } 34 if nx_iot_prov_state_is_valid(PROV_ST_DONE) != 1 { return 2 } 35 if nx_iot_prov_state_is_valid(PROV_ST_N) != 0 { return 3 } 36 if nx_iot_prov_state_is_valid(-1) != 0 { return 4 } 37 if nx_iot_prov_action_is_valid(PROV_ACT_PUSH_CREDS) != 1 { return 5 } 38 if nx_iot_prov_action_is_valid(PROV_ACT_N) != 0 { return 6 } 39 if nx_iot_prov_event_is_valid(PROV_EV_ANCHOR_OK) != 1 { return 7 } 40 if nx_iot_prov_event_is_valid(PROV_EV_N) != 0 { return 8 } 41 if nx_iot_prov_event_is_valid(-1) != 0 { return 9 } 42 if nx_iot_prov_fail_is_valid(PROV_FAIL_PUSH) != 1 { return 10 } 43 if nx_iot_prov_fail_is_valid(PROV_FAIL_N) != 0 { return 11 } 44 if nx_iot_prov_fail_is_valid(-1) != 0 { return 12 } 45 46 // ---- NEVER-BRICK: the whole action alphabet is brick-safe ------- 47 // (CLAUDE.md #26 -- mechanical, not asserted-as-promise) 48 var a: i64 = 0 49 while a < PROV_ACT_N { 50 if nx_iot_prov_action_is_brick_safe(a) != 1 { return 20 } 51 if nx_iot_prov_action_writes_firmware(a) != 0 { return 21 } 52 a = a + 1 53 } 54 // FAIL-SAFE: an out-of-range / future action defaults to firmware-write 55 // (= RED) and is NOT brick-safe. This is what makes the guarantee 56 // hold by construction for actions not yet invented. 57 if nx_iot_prov_action_writes_firmware(PROV_ACT_N) != 1 { return 22 } 58 if nx_iot_prov_action_is_brick_safe(PROV_ACT_N) != 0 { return 23 } 59 if nx_iot_prov_action_is_brick_safe(-1) != 0 { return 24 } 60 if nx_iot_prov_action_writes_firmware(9999) != 1 { return 25 } 61 62 // ---- init ------------------------------------------------------ 63 let s: *IotProvSession = sys_mmap(64) as *IotProvSession 64 if nx_iot_prov_init(s, 0) != 0 { return 40 } 65 if nx_iot_prov_state(s) != PROV_ST_IDLE { return 41 } 66 if nx_iot_prov_vendor(s) != NX_IOT_VENDOR_UNKNOWN { return 42 } 67 if nx_iot_prov_fail_reason(s) != PROV_FAIL_NONE { return 43 } 68 if nx_iot_prov_attempts(s) != 0 { return 44 } 69 if nx_iot_prov_logical_id(s) != 0 { return 45 } 70 if nx_iot_prov_action(s) != PROV_ACT_NONE { return 46 } 71 if nx_iot_prov_ev_count(s) != 0 { return 47 } 72 if s.max_attempts != NX_IOT_PROV_MAX_ATTEMPTS { return 48 } 73 // override + null guard 74 if nx_iot_prov_init(s, 5) != 0 { return 49 } 75 if s.max_attempts != 5 { return 50 } 76 if nx_iot_prov_init(s, -3) != 0 { return 51 } 77 if s.max_attempts != NX_IOT_PROV_MAX_ATTEMPTS { return 52 } 78 if nx_iot_prov_init(0 as *IotProvSession, 0) != PROV_FAIL_BAD_ARG { return 53 } 79 80 // ---- pairing-SSID filter --------------------------------------- 81 if nx_iot_prov_is_pairing_ssid("TP-LINK_HS210_C209", 18) != 1 { return 54 } 82 if nx_iot_prov_is_pairing_ssid("SmartLife-1234", 14) != 1 { return 55 } 83 if nx_iot_prov_is_pairing_ssid("wiz_a1b2c3", 10) != 1 { return 56 } 84 if nx_iot_prov_is_pairing_ssid("MyHomeWiFi", 10) != 0 { return 57 } 85 if nx_iot_prov_is_pairing_ssid("-", 0) != 0 { return 58 } 86 87 // ---- HAPPY PATH: no manual step, end to end -------------------- 88 if nx_iot_prov_init(s, 0) != 0 { return 60 } 89 90 let r1: i64 = nx_iot_prov_step(s, PROV_EV_START, "-", 0, 0) 91 if r1 != PROV_ACT_SCAN { return 61 } 92 if nx_iot_prov_state(s) != PROV_ST_SCANNING { return 62 } 93 if nx_iot_prov_action_is_brick_safe(r1) != 1 { return 63 } 94 if nx_iot_prov_action(s) != PROV_ACT_SCAN { return 64 } 95 96 let r2: i64 = nx_iot_prov_step(s, PROV_EV_AP_FOUND, "TP-LINK_HS210_C209", 18, 0) 97 if r2 != PROV_ACT_JOIN_AP { return 65 } 98 if nx_iot_prov_state(s) != PROV_ST_JOINING { return 66 } 99 if nx_iot_prov_vendor(s) != NX_IOT_VENDOR_KASA { return 67 } 100 if nx_iot_prov_action_is_brick_safe(r2) != 1 { return 68 } 101 102 let r3: i64 = nx_iot_prov_step(s, PROV_EV_JOIN_OK, "-", 0, 0) 103 if r3 != PROV_ACT_PUSH_CREDS { return 69 } 104 if nx_iot_prov_state(s) != PROV_ST_PUSHING { return 70 } 105 if nx_iot_prov_action_is_brick_safe(r3) != 1 { return 71 } 106 107 let r4: i64 = nx_iot_prov_step(s, PROV_EV_PUSH_OK, "-", 0, 0) 108 if r4 != PROV_ACT_REJOIN_HOME { return 72 } 109 if nx_iot_prov_state(s) != PROV_ST_AWAIT_REJOIN { return 73 } 110 if nx_iot_prov_action_is_brick_safe(r4) != 1 { return 74 } 111 112 let r5: i64 = nx_iot_prov_step(s, PROV_EV_REJOIN_OK, "-", 0, 0) 113 if r5 != PROV_ACT_VERIFY { return 75 } 114 if nx_iot_prov_state(s) != PROV_ST_VERIFYING { return 76 } 115 if nx_iot_prov_action_is_brick_safe(r5) != 1 { return 77 } 116 117 let r6: i64 = nx_iot_prov_step(s, PROV_EV_VERIFY_OK, "-", 0, 0) 118 if r6 != PROV_ACT_ANCHOR { return 78 } 119 if nx_iot_prov_state(s) != PROV_ST_ANCHORING { return 79 } 120 if nx_iot_prov_action_is_brick_safe(r6) != 1 { return 80 } 121 122 // anchor adopt happened in the runner; it feeds back logical_id 7 123 let r7: i64 = nx_iot_prov_step(s, PROV_EV_ANCHOR_OK, "-", 0, 7) 124 if r7 != PROV_ACT_REPORT_DONE { return 81 } 125 if nx_iot_prov_state(s) != PROV_ST_DONE { return 82 } 126 if nx_iot_prov_logical_id(s) != 7 { return 83 } 127 if nx_iot_prov_fail_reason(s) != PROV_FAIL_NONE { return 84 } 128 if nx_iot_prov_is_success(s) != 1 { return 85 } 129 if nx_iot_prov_is_terminal(s) != 1 { return 86 } 130 if nx_iot_prov_action_is_brick_safe(r7) != 1 { return 87 } 131 if nx_iot_prov_ev_count(s) != 7 { return 88 } 132 133 // ---- terminal stickiness + idempotency (CLAUDE.md #10) --------- 134 let rt: i64 = nx_iot_prov_step(s, PROV_EV_START, "-", 0, 0) 135 if rt != PROV_ACT_NONE { return 100 } 136 if nx_iot_prov_state(s) != PROV_ST_DONE { return 101 } 137 if nx_iot_prov_is_success(s) != 1 { return 102 } 138 if nx_iot_prov_logical_id(s) != 7 { return 103 } 139 140 // ---- FAIL: scan found no pairing AP ---------------------------- 141 if nx_iot_prov_init(s, 0) != 0 { return 110 } 142 nx_iot_prov_step(s, PROV_EV_START, "-", 0, 0) 143 let f1: i64 = nx_iot_prov_step(s, PROV_EV_AP_NONE, "-", 0, 0) 144 if f1 != PROV_ACT_REPORT_FAIL { return 111 } 145 if nx_iot_prov_state(s) != PROV_ST_FAILED { return 112 } 146 if nx_iot_prov_fail_reason(s) != PROV_FAIL_NO_AP { return 113 } 147 if nx_iot_prov_is_terminal(s) != 1 { return 114 } 148 if nx_iot_prov_is_success(s) != 0 { return 115 } 149 150 // ---- FAIL: pairing AP we have no driver for (honest dead-end) --- 151 if nx_iot_prov_init(s, 0) != 0 { return 120 } 152 nx_iot_prov_step(s, PROV_EV_START, "-", 0, 0) 153 let f2: i64 = nx_iot_prov_step(s, PROV_EV_AP_FOUND, "MyHomeWiFi", 10, 0) 154 if f2 != PROV_ACT_REPORT_FAIL { return 121 } 155 if nx_iot_prov_state(s) != PROV_ST_FAILED { return 122 } 156 if nx_iot_prov_fail_reason(s) != PROV_FAIL_UNKNOWN_VENDOR { return 123 } 157 if nx_iot_prov_vendor(s) != NX_IOT_VENDOR_UNKNOWN { return 124 } 158 159 // ---- bounded retry RECOVERS: transient join failures then OK ---- 160 if nx_iot_prov_init(s, 0) != 0 { return 130 } // default max = 3 161 nx_iot_prov_step(s, PROV_EV_START, "-", 0, 0) 162 nx_iot_prov_step(s, PROV_EV_AP_FOUND, "TP-LINK_HS210_C209", 18, 0) 163 let j1: i64 = nx_iot_prov_step(s, PROV_EV_JOIN_FAIL, "-", 0, 0) 164 if j1 != PROV_ACT_JOIN_AP { return 131 } // retry, not fail 165 if nx_iot_prov_state(s) != PROV_ST_JOINING { return 132 } 166 if nx_iot_prov_attempts(s) != 1 { return 133 } 167 let j2: i64 = nx_iot_prov_step(s, PROV_EV_JOIN_FAIL, "-", 0, 0) 168 if j2 != PROV_ACT_JOIN_AP { return 134 } 169 if nx_iot_prov_attempts(s) != 2 { return 135 } 170 let j3: i64 = nx_iot_prov_step(s, PROV_EV_JOIN_OK, "-", 0, 0) 171 if j3 != PROV_ACT_PUSH_CREDS { return 136 } // recovered 172 if nx_iot_prov_state(s) != PROV_ST_PUSHING { return 137 } 173 if nx_iot_prov_attempts(s) != 0 { return 138 } // counter reset on advance 174 175 // ---- retry EXHAUSTED at the cap -> FAIL JOIN ------------------- 176 if nx_iot_prov_init(s, 2) != 0 { return 140 } // max = 2 177 nx_iot_prov_step(s, PROV_EV_START, "-", 0, 0) 178 nx_iot_prov_step(s, PROV_EV_AP_FOUND, "TP-LINK_HS210_C209", 18, 0) 179 let k1: i64 = nx_iot_prov_step(s, PROV_EV_JOIN_FAIL, "-", 0, 0) 180 if k1 != PROV_ACT_JOIN_AP { return 141 } // attempt 1 < 2, retry 181 let k2: i64 = nx_iot_prov_step(s, PROV_EV_JOIN_FAIL, "-", 0, 0) 182 if k2 != PROV_ACT_REPORT_FAIL { return 142 } // attempt 2, give up 183 if nx_iot_prov_state(s) != PROV_ST_FAILED { return 143 } 184 if nx_iot_prov_fail_reason(s) != PROV_FAIL_JOIN { return 144 } 185 186 // ---- PUSH fail exhausted (device left SAFE in pairing) --------- 187 if nx_iot_prov_init(s, 1) != 0 { return 150 } // max = 1: one fail exhausts 188 nx_iot_prov_step(s, PROV_EV_START, "-", 0, 0) 189 nx_iot_prov_step(s, PROV_EV_AP_FOUND, "TP-LINK_HS210_C209", 18, 0) 190 nx_iot_prov_step(s, PROV_EV_JOIN_OK, "-", 0, 0) 191 let p1: i64 = nx_iot_prov_step(s, PROV_EV_PUSH_FAIL, "-", 0, 0) 192 if p1 != PROV_ACT_REPORT_FAIL { return 151 } 193 if nx_iot_prov_state(s) != PROV_ST_FAILED { return 152 } 194 if nx_iot_prov_fail_reason(s) != PROV_FAIL_PUSH { return 153 } 195 196 // ---- REJOIN timeout -------------------------------------------- 197 if nx_iot_prov_init(s, 1) != 0 { return 160 } 198 nx_iot_prov_step(s, PROV_EV_START, "-", 0, 0) 199 nx_iot_prov_step(s, PROV_EV_AP_FOUND, "TP-LINK_HS210_C209", 18, 0) 200 nx_iot_prov_step(s, PROV_EV_JOIN_OK, "-", 0, 0) 201 nx_iot_prov_step(s, PROV_EV_PUSH_OK, "-", 0, 0) 202 let q1: i64 = nx_iot_prov_step(s, PROV_EV_REJOIN_FAIL, "-", 0, 0) 203 if q1 != PROV_ACT_REPORT_FAIL { return 161 } 204 if nx_iot_prov_fail_reason(s) != PROV_FAIL_REJOIN_TIMEOUT { return 162 } 205 206 // ---- VERIFY fail ----------------------------------------------- 207 if nx_iot_prov_init(s, 1) != 0 { return 170 } 208 nx_iot_prov_step(s, PROV_EV_START, "-", 0, 0) 209 nx_iot_prov_step(s, PROV_EV_AP_FOUND, "TP-LINK_HS210_C209", 18, 0) 210 nx_iot_prov_step(s, PROV_EV_JOIN_OK, "-", 0, 0) 211 nx_iot_prov_step(s, PROV_EV_PUSH_OK, "-", 0, 0) 212 nx_iot_prov_step(s, PROV_EV_REJOIN_OK, "-", 0, 0) 213 let v1: i64 = nx_iot_prov_step(s, PROV_EV_VERIFY_FAIL, "-", 0, 0) 214 if v1 != PROV_ACT_REPORT_FAIL { return 171 } 215 if nx_iot_prov_fail_reason(s) != PROV_FAIL_VERIFY { return 172 } 216 217 // ---- ANCHOR fail (e.g. registry full) -------------------------- 218 if nx_iot_prov_init(s, 1) != 0 { return 180 } 219 nx_iot_prov_step(s, PROV_EV_START, "-", 0, 0) 220 nx_iot_prov_step(s, PROV_EV_AP_FOUND, "TP-LINK_HS210_C209", 18, 0) 221 nx_iot_prov_step(s, PROV_EV_JOIN_OK, "-", 0, 0) 222 nx_iot_prov_step(s, PROV_EV_PUSH_OK, "-", 0, 0) 223 nx_iot_prov_step(s, PROV_EV_REJOIN_OK, "-", 0, 0) 224 nx_iot_prov_step(s, PROV_EV_VERIFY_OK, "-", 0, 0) 225 let w1: i64 = nx_iot_prov_step(s, PROV_EV_ANCHOR_FAIL, "-", 0, 0) 226 if w1 != PROV_ACT_REPORT_FAIL { return 181 } 227 if nx_iot_prov_state(s) != PROV_ST_FAILED { return 182 } 228 if nx_iot_prov_fail_reason(s) != PROV_FAIL_ANCHOR { return 183 } 229 230 // ---- defensive: malformed event is a no-op; null does not crash - 231 if nx_iot_prov_init(s, 0) != 0 { return 190 } 232 let d1: i64 = nx_iot_prov_step(s, 999, "-", 0, 0) // invalid event 233 if d1 != PROV_ACT_NONE { return 191 } 234 if nx_iot_prov_state(s) != PROV_ST_IDLE { return 192 } // unchanged 235 if nx_iot_prov_ev_count(s) != 0 { return 193 } // invalid events do not count 236 let d2: i64 = nx_iot_prov_step(0 as *IotProvSession, PROV_EV_START, "-", 0, 0) 237 if d2 != PROV_ACT_NONE { return 194 } // null guard, no crash 238 239 return 0 240}