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

CheckResultNotes / fix
HTML has no piece/chunk buttonsPASSShow QR + Connect Alby (NWC) + browser wallet
#btn-qr / #btn-pay / #btn-nwc-pay call whole-file APIsPASS→ POST /api/file/invoice then claim
Piece path stays CLI/APIPASSDead piece helpers remain unwired; get --piece + /api/piece/*
Cache bustPASSapp.js?v=alby-nwc-1


1b) Unpaid Get-file must stay locked

CheckExpected
Select catalog file with no prior unlock in this browserProgress shows 0 / N · locked until pay; 0 sats paid; pay QR / browser wallet still enabled
/api/download/held/<ih> without unlock_tokenpieces_b64 empty · unlocked: false · no free file bytes
Shared server downloaded from a prior buyerMust not auto-show Done / unlocked for a new visitor
After settled whole-file claimunlock_token issued · Done + “you have the file” · sats paid > 0 · blob save allowed
WebTorrent seed pathUnchanged — 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

PageResultFixes applied
/ Get-file (QR + NWC + WebLN)PASSConnect Alby (NWC) elevated; WebLN fail → prefer NWC if connected, else QR + toast
/ Seed & earn + stats widgetsPASSlud16 label → “where you get paid”; BT honesty box intact
/statsPASSCatalog 10 · server seeders 2 · LN seeders live · no secrets
/demosPASSELI5 stories; CLI example uses get --piece 0 --invoice-only --json
/tosPASSAllowlist + “you pay” wording (no auto-pay)
/media/*PASSScreenshots + webm 200

3) Alby / Lexe PaymentSendingFailed — diagnosis

Bolt11 decode (example whole-file 66 sat = cc0-mp3-seed)

FieldValue
Amount66000 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
Featurespayment_secret required, var_onion_optin required, MPP supported
Expiry3600s
Descriptionh (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. 1. QR = Recommended primary path (any external wallet).
  2. 2. WebLN/NWC failures classified; route failures auto-open QR and toast: Alby could not route to Lexe — use Show QR.
  3. 3. Hint copy documents Alby caveat; Advanced NWC notes Coinos often works.
  4. 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)

Proof pays (box, real sats)

From → ToAmountResult
Lexe NWC → Coinos top-up100 / 120 satPASS (preimage)
Coinos NWC → Lexe whole-file cc0-mp3-seed66 satPASS + claim complete (win-flutes.mp3, 66 pieces)
Coinos NWC → Lexe whole-file mit-tokenizer-stub21 satPASS + claim (vocab.stub, 2 pieces)
CLI get --piece 0 --pay (Coinos NWC) tiny-lm-demo21 satPASS paid+claimed+saved 256 bytes
Lexe NWC → Lexe invoice21 / 66Expected fail: cannot pay ourselves
Alby WebLN → Lexe~66 satFAIL (route) — expected; UI now routes user to QR

4) Bot / thick-client / API matrix

TestResultExit / HTTP
catalog --jsonPASS0 · count 10 · allowlist SPDX
GET /api/catalogPASS200
seed --fixture legal-torrent-seed --lud16 … --seconds 12 --jsonPASS0 · BT announce + lud16
POST /api/seeder/registerPASSok · lud16 set
get --piece 0 --invoice-only --jsonPASS0 · 21 sat floor · bolt11
get --piece 0 --pay --nwc-file coinos --save …PASS0 · paid+claimed+verified
get --whole --invoice-only + external pay + /api/file/claimPASSclaim complete
seed-local --prove-blockedPASSsite_blocked: true
POST /api/magnet /api/magnet/add /api/torrent/addPASS403 blocked:true
Bad fixturePASSexit 2 · single JSON on stdout (fixed double-print _die)
Bad flagPASSexit 2
Pay missing NWC filePASSexit 3
No subcommandPASSexit 2

5) Seed / WebTorrent

CheckResult
CLI BT seed listen + announcePASS (bittorrent.announces ≥ 1, port 6899)
Server webseed fixtures presentPASS (MIT + CC0 under /webseed/)
Browser “I’m seeding” + live peersManual / prior media (docs/media/02c_seed_wt_stats.png) — depends on external swarm peers
Optional local magnet never hits catalogPASS (client-only; server magnet POST 403)

6) UX friction fixed this pass

FrictionFix
Alby PaymentSendingFailed dead-endAuto-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 JSONstdout once
Cache / PUBLIC_URL stalerefreshed 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


9) Alby 1-click + paste failure — UX pass (2026-09-26 ~8:52 PM PDT)

What “1-click / Alby” was

Fixes shipped (?v=alby-lexe-qr-5)

  1. 1. Primary path = QR with explicit wallets: Phoenix / Coinos / Wallet of Satoshi.
  2. 2. Browser wallet demoted to optional; labels “Try / Retry browser wallet”.
  3. 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. 4. Copy-invoice toast warns Alby paste often fails; pay-box strip repeats wallet reco.
  5. 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).