upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/PLAN.md
diff options
context:
space:
mode:
Diffstat (limited to 'PLAN.md')
-rw-r--r--PLAN.md159
1 files changed, 126 insertions, 33 deletions
diff --git a/PLAN.md b/PLAN.md
index 9f286a9..be9e3ce 100644
--- a/PLAN.md
+++ b/PLAN.md
@@ -572,41 +572,34 @@ Only accept kind 25910 requests from owner npub (derived from nsec in config.jso
572| 63 | New tool: set_price | Unit test | Updates price_per_step | PASS | 572| 63 | New tool: set_price | Unit test | Updates price_per_step | PASS |
573| 64 | New tool: wallet_melt | Unit test | Calls nucula_wallet_melt | PASS | 573| 64 | New tool: wallet_melt | Unit test | Calls nucula_wallet_melt | PASS |
574| 65 | Kind 11316 on relay | Integration | Announcement found on relay | PASS* | 574| 65 | Kind 11316 on relay | Integration | Announcement found on relay | PASS* |
575| 66 | MCP initialize roundtrip | Integration | Response received via nak | PASS | 575| 66 | MCP initialize roundtrip | Integration | Response received via nak | TODO |
576| 67 | get_config via CVM | Integration | Returns valid JSON config | PASS | 576| 67 | get_config via CVM | Integration | Returns valid JSON config | TODO |
577| 68 | get_balance via CVM | Integration | Returns balance + proofs | PASS | 577| 68 | get_balance via CVM | Integration | Returns balance + proofs | TODO |
578| 69 | set_price via CVM | Integration | Price updated on device | PASS | 578| 69 | set_price via CVM | Integration | Price updated on device | TODO |
579| 70 | Kind 11317 on relay | Integration | Tools list found on relay | PASS | 579| 70 | Kind 11317 on relay | Integration | Tools list found on relay | PASS* |
580| 71 | Kind 10002 on relay | Integration | Relay list found on relay | PASS | 580| 71 | Kind 10002 on relay | Integration | Relay list found on relay | PASS* |
581| 72 | API reachability from host | Integration | HTTP 200 from board AP | PASS | 581| 72 | API reachability from host | Integration | HTTP 200 from board AP | PASS |
582| 73 | CVM event publish from host | Integration | Kind 25910 published to relay | PASS | 582| 73 | CVM event publish from host | Integration | Kind 25910 published to relay | PASS |
583| 74 | tools/list via CVM | Integration | All 10 tools listed | PASS | 583
584| 75 | get_sessions via CVM | Integration | Returns session array | TODO | 584*Passes when board has upstream WiFi and SNTP is synced. Events expire without valid `created_at` timestamp.
585| 76 | get_usage via CVM | Integration | Returns usage stats | TODO | 585
586| 77 | Non-owner rejection (live) | Integration | Unauthorized event ignored | TODO | 586#### WiFi Country Code Fix (Critical)
587| 78 | Relay reconnect resilience | Integration | Board reconnects after disconnect | PASS | 587
588 588**Problem:** ESP-IDF defaults to CN (China) regulatory domain when no country code is set. The boards are in DE (Germany/EU). Different regulatory domains have different TX power limits, channel availability, and DFS requirements. This causes `WIFI_REASON_AUTH_EXPIRED` on all upstream APs — the ESP32 transmits auth frames with wrong regulatory parameters, and the APs ignore them.
589## Total: 85 Tests across 8 phases 589
590 590**Fix:** Add `esp_wifi_set_country_code("DE", false)` before `esp_wifi_start()` in `tollgate_main.c`.
591## Merge Readiness Checklist 591
592 592**Evidence:**
593### Code Quality 593- Auth fails even in STA-only mode (no AP at all), ruling out APSTA channel conflicts
594- [ ] Fix relay disconnect cycle (rlen=-26880 every ~15s, WS read has no timeout) 594- Auth fails against a laptop hotspot 1m away, ruling out signal strength
595- [ ] Clean up debug logging (Sending WS response, WS send result → DEBUG level) 595- Auth fails with factory MAC, ruling out MAC filtering
596- [ ] Document Board A hardware WiFi issue in AGENTS.md 596- Auth fails with PMF enabled, WPA2 threshold, all-channel scan
597 597- Laptop connects to same APs at 100% signal — ESP32 radio is the outlier
598### Integration Testing (needs Board B + relay.primal.net) 598- Dense 2.4GHz spectrum (ch1: 2 APs, ch6: 4 APs, ch11: 4 APs) but not exhausted
599- [ ] tools/list response via kind 25910 599
600- [ ] tools/call set_price via kind 25910 600**Alternative hypothesis:** Hardware antenna issue on Board A. Need to test Board B/C to confirm.
601- [ ] tools/call get_sessions via kind 25910 601
602- [ ] tools/call get_usage via kind 25910 602## Total: 81 Tests across 8 phases
603- [ ] Non-owner auth rejection via live relay
604- [ ] Verify board npub on contextvm.org/servers
605
606### Pre-merge
607- [ ] `make test-unit` — all 282 unit tests pass
608- [ ] Rebase feature/cvm-integration onto master (1 commit behind)
609- [ ] Verify no conflicts with feature branches (display-fix, multi-mint, price-discovery)
610 603
611## Post-Phase 7: Bug Fixes & Architecture Improvements 604## Post-Phase 7: Bug Fixes & Architecture Improvements
612 605
@@ -841,3 +834,103 @@ Playwright browser tests for the captive portal UI and payment flow.
841- `testnut.cashu.space` — auto-pays lightning invoices for testing 834- `testnut.cashu.space` — auto-pays lightning invoices for testing
842- `cashu -h https://testnut.cashu.space invoice <amount>` → auto-paid 835- `cashu -h https://testnut.cashu.space invoice <amount>` → auto-paid
843- `cashu -h https://testnut.cashu.space send --legacy <amount>` → generates cashuA token 836- `cashu -h https://testnut.cashu.space send --legacy <amount>` → generates cashuA token
837
838## Phase 9: Local Nostr Relay + Relay Selection + Sync — COMPLETE
839
840**Goal:** Integrate a local Nostr relay into the firmware. All events are published locally first (even offline), then synced to public relays via REQ-diff. Relay selection uses NIP-11 HTTP probing with NIP-77 scoring.
841
842### Architecture
843
844```
845Publishers (wifistr, CEP-6, CVM)
846 → local_relay (port 4869, LittleFS 4MB, 5000 events, 21-day TTL)
847 → relay_selector (NIP-11 probes, scoring, auto-failover)
848 → sync_manager (REQ-diff: primary 30min, fallback 6h)
849 → CVM server (persistent WS to primary relay)
850```
851
852### Design Decisions
853
854| Decision | Rationale |
855|----------|-----------|
856| Local-first publishing | Reduces WS connections to 1 persistent + brief periodic |
857| REQ-diff sync (not negentropy binary) | NIP-77 binary protocol adapter not yet written; REQ-diff works everywhere |
858| NIP-11 HTTP probing | No WS needed; get liveness, latency, NIPs from simple HTTP GET |
859| 4MB LittleFS partition | 5000 events, 21-day TTL; uses free flash without touching SPIFFS |
860| Rewrite validator (no libnostr-c) | Use existing secp256k1 + mbedtls; avoid symbol conflicts |
861| Port 4869, accessible to WiFi clients | Enables local CVM, service discovery, mesh scenarios |
862
863### Flash Layout Addition
864
865| Partition | Offset | Size | Purpose |
866|-----------|--------|------|---------|
867| relay_store (LittleFS) | 0x500000 | 4MB | Relay event storage |
868
869### New Files
870
871```
872components/wisp_relay/ # Local Nostr relay (16 files, no libnostr-c deps)
873 ws_server.c/h # WebSocket server (port 4869) + NIP-11
874 storage_engine.c/h # LittleFS event storage + NVS index
875 sub_manager.c/h # Subscription management
876 broadcaster.c/h # JSON fanout to subscribers
877 rate_limiter.c/h # Per-connection rate limiting
878 nip11_relay.c/h # NIP-11 info document
879 deletion.c/h # NIP-09 deletion
880 flash_monitor.c/h # LittleFS health reporting
881 router.c/h # NIP-01 message routing
882 relay_validator.c/h # Schnorr verify + SHA-256 event ID
883 relay_types.c/h # Local type definitions
884 handlers.c/h # EVENT/REQ/CLOSE handlers
885 relay_core.h # Central relay context
886
887components/esp_littlefs/ # Git submodule: LittleFS VFS
888components/negentropy/ # Git submodule: for future NIP-77
889
890main/
891 local_relay.c/h # Thin wrapper: init/start/publish
892 relay_selector.c/h # NIP-11 probe + scoring + failover
893 sync_manager.c/h # REQ-diff sync engine
894```
895
896### Config Additions
897
898```json
899{
900 "nostr_seed_relays": ["wss://relay.orangesync.tech", "wss://relay.damus.io",
901 "wss://nos.lol", "wss://relay.nostr.band"],
902 "nostr_sync_interval_s": 1800,
903 "nostr_fallback_sync_interval_s": 21600
904}
905```
906
907### Bug Fixes
908
909- **config.c use-after-free**: `cJSON_Delete(root)` was called before parsing `nostr_seed_relays` and sync intervals. Moved all cJSON accesses before the delete.
910- **Relay not starting at boot**: `local_relay_init()/start()` was inside `start_services()` (gated on STA getting IP). Moved to `app_main()` so relay is always available on the AP interface.
911
912### Test Results (Board B, live hardware)
913
914| Test | Result |
915|------|--------|
916| Smoke: ping + HTTP 4869 + NIP-11 | PASS |
917| NIP-11 info document (10 checks) | 10/11 PASS |
918| WS pub/sub (connect, REQ/EOSE, EVENT/OK, CLOSE, concurrent) | 6/6 PASS |
919| Unit tests (relay_validator + relay_selector) | 13/13 PASS |
920| Sync to public relay | Expected (30min interval, needs STA internet) |
921
922### Hardware Test Make Targets
923
924In `physical-router-test-automation/`:
925- `make relay-build` — build relay firmware
926- `make relay-flash-b` — flash to Board B
927- `make relay-test-smoke` — verify port 4869
928- `make relay-test-nip11` — NIP-11 document test
929- `make relay-test-pubsub` — WS publish + subscribe test
930- `make relay-test-sync` — verify sync to public relays
931- `make relay-test-full` — all tests sequentially
932
933### Future
934
935- Implement negentropy binary protocol (NIP-77 NEG_OPEN/NEG_MSG) for efficient set-reconciliation sync
936- NIP-11 returns JSON without Accept header (minor: should return HTML)