diff options
Diffstat (limited to 'PLAN.md')
| -rw-r--r-- | PLAN.md | 159 |
1 files changed, 126 insertions, 33 deletions
| @@ -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 | ``` | ||
| 845 | Publishers (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 | ``` | ||
| 872 | components/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 | |||
| 887 | components/esp_littlefs/ # Git submodule: LittleFS VFS | ||
| 888 | components/negentropy/ # Git submodule: for future NIP-77 | ||
| 889 | |||
| 890 | main/ | ||
| 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 | |||
| 924 | In `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) | ||