1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
# Relay Hardening + Remaining Work — Implementation Plan
## Overview
Post-merge cleanup and remaining work on the `feature/relay-hardening` branch. Covers CVM+relay integration tests, test infrastructure polish, documentation updates, display testing, cross-board payment, OpenWRT interop, and NIP-77 negentropy adapter.
**Branch:** `feature/relay-hardening` (from `master` at `81f2dc5`)
**Worktree:** `/home/c03rad0r/esp32-tollgate-hardening`
**Main repo:** `/home/c03rad0r/esp32-tollgate`
---
## Checklist
### Phase 1: CVM + Relay Integration (Group A)
- [ ] Write `tests/integration/test-cvm-relay.mjs` — CVM tool call via local relay (ws://BOARD_IP:4869)
- Connect WS to local relay
- Subscribe to kind 25910 for board's npub
- Verify CEP-6 announcements (kind 11316/11317/10002) stored in local relay
- Publish kind 25910 MCP request via local relay
- Verify response received via local relay
- [ ] Add `test-cvm-relay` make target to main `Makefile` (with board lock)
- [ ] Add `test-cvm-relay` make target to `physical-router-test-automation/esp32/Makefile` (with board lock)
- [ ] Add passthrough target to top-level `physical-router-test-automation/Makefile`
- [ ] End-to-end MCP tools/call roundtrip via kind 25910 on public relay
- Extend existing `cvm-test-tool` or write new test
- Publish kind 25910 to public relay, verify response on public relay
- Test at least `get_config` and `get_balance`
- [ ] Add `test-cvm-e2e` make target to main `Makefile` (with board lock)
- [ ] Verify board npub on contextvm.org/servers (manual check, document result)
- [ ] Add `test-cvm-e2e` make target to `physical-router-test-automation/esp32/Makefile`
- [ ] Flash firmware with relay to Board B, lock board, run all CVM+relay tests
### Phase 2: Test Infrastructure Cleanup (Group B)
- [x] IP fallbacks already correct (all tests use `process.env.TOLLGATE_IP || '10.192.45.1'`, no `192.168.4.1`)
- [x] Test directories already at correct paths (`tests/integration/`, `tests/e2e/`)
- [x] Integration tests already in `tests/integration/` (api, network, phase2, smoke, test-cvm, test-reset-auth, test-session-expiry, test-dns-firewall, test-local-relay, test-relay-nip11)
- [x] E2E tests already in `tests/e2e/` (captive-portal.spec, interop-happy-path.spec)
- [ ] Add `test-local-relay` and `test-relay-nip11` targets to main `Makefile` (with board lock)
- [ ] Add `smoke` make target alias to `physical-router-test-automation/esp32/Makefile` for relay firmware
- [ ] Per-test context isolation in `tests/e2e/playwright.config.mjs`
- [ ] Verify Playwright `.webm` video recording in `tests/e2e/test-results/`
- [ ] Run full integration test suite on Board B to verify nothing regressed
### Phase 3: Documentation (Group C)
- [ ] Update AGENTS.md: firewall description → "per-client NAT filter via LWIP_HOOK_IP4_CANFORWARD"
- [ ] Update AGENTS.md: session.c description → remove "spent-secret tracking"
- [ ] Update AGENTS.md: add display module docs (display.c/h, font.c/h, QR cycling, states)
- [ ] Update AGENTS.md: add relay hardening make targets to test instructions
- [ ] Verify CVM announcements on relay.primal.net (Board B with internet)
- Kind 11316 server announcement
- Kind 11317 tools list
- Kind 10002 relay list
- [ ] Update CHECKLIST.md: mark verified items, add relay-hardening items
### Phase 4: Display Testing on Board C (Group D.1)
- [ ] Add unit test for `escape_wifi_field()` in `tests/unit/test_display.c`
- Test: no special chars → no escaping
- Test: semicolons, colons, backslashes, commas, quotes → backslash-escaped
- Test: multiple special chars in one string
- Test: empty string
- [ ] Add unit test for QR matrix generation in `tests/unit/test_display.c`
- Test: valid QR matrix for various string lengths
- Test: WIFI: URI format correctness
- [ ] Update `tests/unit/Makefile` with `test_display` target
- [ ] Lock Board C (`make lock-c PHASE="display testing"`)
- [ ] Flash firmware to Board C at `/dev/ttyACM3`
- [ ] Verify boot screen shows "TollGate starting..."
- [ ] Verify QR code renders on display
- [ ] Verify Wi-Fi QR is scannable by Android/iOS camera
- [ ] Verify portal URL QR is scannable and loads captive portal
- [ ] Verify QR cycling (Wi-Fi ↔ Portal URL every 5s)
- [ ] Unlock Board C
### Phase 5: Board B Config + Cross-Board Payment (Group D.2)
- [ ] Create Board B `config.json` with unique nsec (`9af47906b45aca5e238390f3d03c8274e154198e81aa2095065627d1e61ca968`)
- Derived identity: SSID `TollGate-b96d80`, AP IP `10.185.47.1`, AP MAC `fe:08:f7:b9:6d:80`
- [ ] Lock Board B (`make lock-b PHASE="Board B config + cross-board test"`)
- [ ] Flash Board B with new config
- [ ] Verify Board B boots with different SSID/IP from Board A
- [ ] Connect laptop to Board B, verify captive portal works
- [ ] Cross-board payment test: Board B pays Board A (Scenario 5)
- Board B as STA connects to Board A's AP
- Board B auto-detects Board A as upstream TollGate (kind 10021)
- Board B wallet creates token, POSTs to Board A
- Verify Board B gets internet through Board A
- [ ] Write integration test `tests/integration/test-cross-board.mjs`
- [ ] Add `test-cross-board` make target to main `Makefile` and physical-router-test-automation
- [ ] Unlock Board B
### Phase 6: OpenWRT Interop (Group D.3)
- [ ] SSH to `root@10.47.41.1`, verify `tollgate-wrt` still running
- [ ] Test `curl http://10.47.41.1:2121/` — verify kind=10021 response
- [ ] Investigate `nofee.testnut.cashu.space` API compatibility
- [ ] Document findings in CHECKLIST.md or OpenWRT interop notes
### Phase 7: NIP-77 Negentropy Adapter (Group D.4)
- [ ] Write `main/negentropy_storage.c/h` — adapter from wisp storage to negentropy API
- `negentropy_storage_init()` — wrap storage_engine event iterator
- `negentropy_get_items()` — iterate stored events, return (timestamp, event_id) pairs
- `negentropy_insert_items()` — insert reconciled events from remote
- [ ] Modify `sync_manager.c` — add negentropy sync path alongside REQ-diff
- Detect NIP-77 support from relay_selector (NIP-77 flag)
- If primary supports NIP-77: use NEG_OPEN/NEG_MSG instead of REQ-diff
- If primary doesn't support NIP-77: fall back to REQ-diff
- [ ] Add `tests/unit/test_negentropy_storage.c` — unit test with mock ID sets
- [ ] Update `tests/unit/Makefile` with `test_negentropy_storage` target
- [ ] Flash to Board B, verify sync with NIP-77 capable relay (orangesync)
---
## Hardware Access Rules
**ALWAYS acquire board lock before any hardware access:**
```bash
# In physical-router-test-automation/esp32/
make lock-b PHASE="relay integration testing"
make lock-c PHASE="display testing"
# Or via main repo
make lock-b PHASE="cross-board payment test"
```
**Make targets that touch hardware MUST use board locks:**
- All `flash-*` targets
- All `test-*` targets that run against live boards
- All `monitor-*` targets
**Make targets that DON'T need locks:**
- `test-unit` (host-only, no hardware)
- `build` (compile only)
- `cvm-pubkey` (read-only query)
**Always release lock when done:**
```bash
make unlock-b
make unlock-c
```
## Board Reference
| Board | Port | Factory MAC | SSID | AP IP | nsec | Use |
|-------|------|-------------|------|-------|------|-----|
| A | `/dev/ttyACM0` | `94:a9:90:2e:37:7c` | `TollGate-B96D80` | `10.185.47.1` | `9af47906...` | Primary test (WiFi broken) |
| B | `/dev/ttyACM1` | `fc:01:2c:c5:50:50` | `TollGate-C0E9CA` | `10.192.45.1` | default | Relay + CVM testing |
| C | `/dev/ttyACM3` | `20:6e:f1:98:d7:08` | TBD | TBD | TBD | Display testing |
## Test Execution Order
1. **No hardware needed:** `make test-unit` — verify all unit tests pass
2. **Board B (lock required):** `make lock-b` → flash → CVM+relay tests → cross-board → `make unlock-b`
3. **Board C (lock required):** `make lock-c` → flash → display tests → `make unlock-c`
4. **No hardware:** documentation updates, AGENTS.md, CHECKLIST.md
5. **OpenWRT (separate):** SSH checks, no board lock needed
## Commit Strategy
- Commit + push after each phase completes
- Commit + push every time a test passes that previously didn't pass
- Squash into single commit before merging back to master
|