7.4 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 01-federation-mesh-hardening | 19 | execute | 1 |
|
false |
|
|
handle_lnd_createinvoice posts to LND's REST /v1/invoices with only value
and memo. LND defaults private to false, so the returned invoice carries
route_hints: []. Private channels are not propagated through public gossip, so
a sender has no way to find a route — the invoice is unpayable by anyone.
Diagnosed on archy-x250-mad2 (2026-07-31), whose single channel to "Olympus by
ZEUS" is private: true with ~40.8k sats of usable inbound. Three wallet-UI
invoices (10,000 / 5,000 / 500 sats) all had empty route hints and never received
an HTLC. The one invoice that DID settle carries a memo ("Paid to Archipelago
(Order ID: ...)") that appears nowhere in this Rust source — it came from a
separate system (likely BTCPay) that builds invoices correctly. That is why
"some payments have worked" while the wallet's own Receive flow never has.
This is not node-specific. The bug is unconditional; it only manifests where a node lacks a public channel. Any user relying on a private channel has a broken Receive flow today.
<execution_context> @$HOME/.claude/gsd-core/workflows/execute-plan.md @$HOME/.claude/gsd-core/templates/summary.md </execution_context>
Task 1: Embed route hints in wallet-created invoices One field in one JSON body; revert is a single-line change. core/archipelago/src/api/rpc/lnd/wallet.rs - `core/archipelago/src/api/rpc/lnd/wallet.rs` around lines 554-557 — `handle_lnd_createinvoice`'s `invoice_body` construction - `core/archipelago/src/api/rpc/lnd/channels.rs:271,368` — the only current uses of a `private` field (channel OPEN, not invoice creation); confirms the omission is specific to invoices Add `"private": true` to `invoice_body` in `handle_lnd_createinvoice` so LND embeds hop hints for unannounced channels:```rust
let invoice_body = serde_json::json!({
"value": amount_sats.to_string(),
"memo": memo,
"private": true,
});
```
Setting it unconditionally is correct and safe: a route hint is harmless when
the node also has public channels — LND still routes directly over a public
channel when it can, and the hint merely offers an alternate path. Add a
short comment stating why it is unconditional, so a future reader doesn't
"optimize" it back to conditional and silently reintroduce the bug.
Then audit every OTHER invoice-creation call site for the same omission —
grep the tree for `/v1/invoices`, `addinvoice`, hold-invoice, LNURL and any
keysend-adjacent flow. Fix each that should carry route hints; for any that
deliberately should not, record the reason in the SUMMARY. Report the full
list either way.
Post-OTA-release, performed by the device owner:
3. Create an invoice through the **wallet UI** (not raw `lncli`) — e.g. 100 sats.
4. `lncli decodepayreq <invoice>` → `route_hints` populated with the Olympus
channel's `chan_id` (was `[]` before this fix).
5. Pay it from a real external wallet; `lncli listinvoices` shows a non-empty
`htlcs` array and `state: SETTLED`.
<success_criteria>
- Receiving Lightning payments works through the wallet UI on a node whose only channel is private
- No regression for nodes with public channels
- Any other invoice-creation path sharing this omission is fixed or explicitly cleared </success_criteria>