Bitswarm — QA matrix
When: 2026-09-26 9:03 PM PDT
Live: https://output-livecam-classifieds-packets.trycloudflare.com
Local: http://127.0.0.1:8765/
Receive lud16: erudite-jellyfish@lexe.app (Lexe)
Payer used on box: Coinos NWC (grokagent1abd223d@coinos.io)
Exit codes (CLI): 0 ok · 1 error · 2 usage/blocked · 3 pay/claim failed
1) Web Get-file = whole-file only
| Check | Result | Notes / fix |
|---|---|---|
| HTML has no piece/chunk buttons | PASS | Show QR + Connect Alby (NWC) + browser wallet |
#btn-qr / #btn-pay / #btn-nwc-pay call whole-file APIs | PASS | → POST /api/file/invoice then claim |
| Piece path stays CLI/API | PASS | Dead piece helpers remain unwired; get --piece + /api/piece/* |
| Cache bust | PASS | app.js?v=alby-nwc-1 |
1b) Unpaid Get-file must stay locked
| Check | Expected |
|---|---|
| Select catalog file with no prior unlock in this browser | Progress shows 0 / N · locked until pay; 0 sats paid; pay QR / browser wallet still enabled |
/api/download/held/<ih> without unlock_token | pieces_b64 empty · unlocked: false · no free file bytes |
Shared server downloaded from a prior buyer | Must not auto-show Done / unlocked for a new visitor |
| After settled whole-file claim | unlock_token issued · Done + “you have the file” · sats paid > 0 · blob save allowed |
| WebTorrent seed path | Unchanged — seeders still seed/earn |
Root cause fixed: global node.downloaded + free /api/download/held previously let the UI mark 6/6 Done with 0 sats. Held bytes now require a post-pay unlock_token; UI gates Done on unlocked && satsPaid > 0.
2) Human UX pages
| Page | Result | Fixes applied |
|---|---|---|
/ Get-file (QR + NWC + WebLN) | PASS | Connect Alby (NWC) elevated; WebLN fail → prefer NWC if connected, else QR + toast |
/ Seed & earn + stats widgets | PASS | lud16 label → “where you get paid”; BT honesty box intact |
/stats | PASS | Catalog 10 · server seeders 2 · LN seeders live · no secrets |
/demos | PASS | ELI5 stories; CLI example uses get --piece 0 --invoice-only --json |
/tos | PASS | Allowlist + “you pay” wording (no auto-pay) |
/media/* | PASS | Screenshots + webm 200 |
3) Alby / Lexe PaymentSendingFailed — diagnosis
Bolt11 decode (example whole-file 66 sat = cc0-mp3-seed)
| Field | Value |
|---|---|
| Amount | 66000 msat = 66 sat (lnbc660n…) |
Payee (n) | 028fc573… — private Lexe user node (not in public gossip) |
Route hint (r) | via Lexe.app 0314a775… SCID 958241x1043x4, fees 0/0, CLTV 72 |
| Features | payment_secret required, var_onion_optin required, MPP supported |
| Expiry | 3600s |
| Description | h (description_hash) — normal LNURL-pay |
Cause
Not a broken invoice. Destination is Lexe’s private node with a correct route hint through public Lexe.app.
Alby Hub / Alby WebLN often returns PaymentSendingFailed / HTTP 400 because Alby’s channels cannot (or will not) route to Lexe for this hop.
Coinos NWC (and phone wallets that can reach Lexe.app) pay the same bolt11 successfully.
Lexe self-pay correctly errors with We cannot pay ourselves — confirms payee is the site Lexe wallet.
Fix (product)
- 1. QR = Recommended primary path (any external wallet).
- 2. WebLN/NWC failures classified; route failures auto-open QR and toast: Alby could not route to Lexe — use Show QR.
- 3. Hint copy documents Alby caveat; Advanced NWC notes Coinos often works.
- 4. No change to lud16 (still Lexe) — switching receive address would only hide the routing lesson.
Alby NWC elevated (2026-09-26 ~9:03 PM PDT)
- UI: first-class Connect Alby (NWC) card (no longer buried under Advanced).
- Connect-once →
localStoragekeyopen_swarm_payer_nwc(browser only; never logged / never POSTed). - Pay with Alby NWC pays whole-file bolt11 via
@getalby/sdkNWCClient.payInvoice. payBolt11Auto: if NWC connected → prefer NWC; else WebLN; onPaymentSendingFailedauto-try NWC if connected, else QR.- Help: Alby Hub → Connections → Add Connection → copy pairing string (guide).
- Unpaid paywall still locked (
/api/download/heldwithout unlock_token → empty pieces). - Prior proof: Coinos NWC → Lexe pay+claim still the known-good NWC route; Alby Hub NWC is the user-facing path for Alby-only users.
Proof pays (box, real sats)
| From → To | Amount | Result |
|---|---|---|
| Lexe NWC → Coinos top-up | 100 / 120 sat | PASS (preimage) |
Coinos NWC → Lexe whole-file cc0-mp3-seed | 66 sat | PASS + claim complete (win-flutes.mp3, 66 pieces) |
Coinos NWC → Lexe whole-file mit-tokenizer-stub | 21 sat | PASS + claim (vocab.stub, 2 pieces) |
CLI get --piece 0 --pay (Coinos NWC) tiny-lm-demo | 21 sat | PASS paid+claimed+saved 256 bytes |
| Lexe NWC → Lexe invoice | 21 / 66 | Expected fail: cannot pay ourselves |
| Alby WebLN → Lexe | ~66 sat | FAIL (route) — expected; UI now routes user to QR |
4) Bot / thick-client / API matrix
| Test | Result | Exit / HTTP |
|---|---|---|
catalog --json | PASS | 0 · count 10 · allowlist SPDX |
GET /api/catalog | PASS | 200 |
seed --fixture legal-torrent-seed --lud16 … --seconds 12 --json | PASS | 0 · BT announce + lud16 |
POST /api/seeder/register | PASS | ok · lud16 set |
get --piece 0 --invoice-only --json | PASS | 0 · 21 sat floor · bolt11 |
get --piece 0 --pay --nwc-file coinos --save … | PASS | 0 · paid+claimed+verified |
get --whole --invoice-only + external pay + /api/file/claim | PASS | claim complete |
seed-local --prove-blocked | PASS | site_blocked: true |
POST /api/magnet /api/magnet/add /api/torrent/add | PASS | 403 blocked:true |
| Bad fixture | PASS | exit 2 · single JSON on stdout (fixed double-print _die) |
| Bad flag | PASS | exit 2 |
| Pay missing NWC file | PASS | exit 3 |
| No subcommand | PASS | exit 2 |
5) Seed / WebTorrent
| Check | Result |
|---|---|
| CLI BT seed listen + announce | PASS (bittorrent.announces ≥ 1, port 6899) |
| Server webseed fixtures present | PASS (MIT + CC0 under /webseed/) |
| Browser “I’m seeding” + live peers | Manual / prior media (docs/media/02c_seed_wt_stats.png) — depends on external swarm peers |
| Optional local magnet never hits catalog | PASS (client-only; server magnet POST 403) |
6) UX friction fixed this pass
| Friction | Fix |
|---|---|
| Alby PaymentSendingFailed dead-end | Auto-show QR + route toast + Recommended pill |
| Seed label “piece invoices” | → “Lightning address (where you get paid)” |
| Demos said get whole-file by default | → accurate get --piece / --whole |
CLI _die double JSON | stdout once |
| Cache / PUBLIC_URL stale | refreshed tunnel + qa-alby-lexe-4 |
7) How to re-run (box)
cd /workspace/bitswarm && source .venv/bin/activate
export BASE=http://127.0.0.1:8765
export OPEN_SWARM_NWC_FILE=/home/box/stacker-news/nwc-secrets.json # Coinos
python thick-client/seed_cli.py catalog --json
python thick-client/seed_cli.py seed --fixture legal-torrent-seed --lud16 erudite-jellyfish@lexe.app --seconds 10 --json
python thick-client/seed_cli.py get --fixture tiny-lm-demo --piece 0 --pay --save /tmp/p0.bin --json
python thick-client/seed_cli.py get --fixture mit-tokenizer-stub --whole --invoice-only --json
# then NWC-pay bolt11 + POST /api/file/claim
curl -sS -o /dev/null -w '%{http_code}\n' -X POST "$BASE/api/magnet" \
-H 'Content-Type: application/json' -d '{"magnet":"magnet:?xt=urn:btih:deadbeef"}' # 403
Human: open live URL → Get file → Show QR (scan with non-Alby wallet) → wait for unlock.
If testing Alby WebLN: expect failure → UI should reveal QR automatically.
8) Honest gaps
- Alby Hub → Lexe routing not fixable in-app (liquidity/path); mitigated by QR + messaging.
- Coinos balance is small — top up from Lexe before long matrices.
- Browser WebTorrent peer counts may be 0 without external leechers.
- Quick tunnel URL rotates on cloudflared restart — re-read
PUBLIC_URL.txt.
9) Alby 1-click + paste failure — UX pass (2026-09-26 ~8:52 PM PDT)
What “1-click / Alby” was
- WebLN only (
window.webln.enable→sendPayment(bolt11)via#btn-pay/#btn-pay-wallet). - No
alby:URI, nolightning:deep link, nogetalby.com/send(that URL is 404 — verified; do not ship). - Paste into Alby Hub fails with
Error: 400: NodeError: PaymentSendingFailed— routing, not a bad bolt11 (Coinos/Phoenix pay the same invoice).
Fixes shipped (?v=alby-lexe-qr-5)
- 1. Primary path = QR with explicit wallets: Phoenix / Coinos / Wallet of Satoshi.
- 2. Browser wallet demoted to optional; labels “Try / Retry browser wallet”.
- 3. On WebLN/NWC
PaymentSendingFailed(or catch): always show QR + plain toast: Alby often can't reach this wallet — scan the QR with another Lightning app. (does not imply invoice invalid). - 4. Copy-invoice toast warns Alby paste often fails; pay-box strip repeats wallet reco.
- 5. Intentionally no Alby-only deep link (broken
alby.com/send/ Alby still cannot route to Lexe).
How an Alby user should pay Lexe
Show QR → scan/pay with Phoenix, Coinos, or Wallet of Satoshi (or Coinos NWC in Advanced). Do not rely on Alby Hub WebLN or paste for this receive address.
Live
Re-read PUBLIC_URL.txt after any cloudflared restart. Cache-bust: hard-refresh (?v=alby-lexe-qr-5).