Files
archy/.planning/phases/01-federation-mesh-hardening/01-19-SUMMARY.md

4.9 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, requirements-completed, coverage, duration, completed, status
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions requirements-completed coverage duration completed status
01-federation-mesh-hardening 19 lightning
lnd
invoices
route-hints
private-channels
wallet
phase provides
01-federation-mesh-hardening The two existing LND invoice-creation call sites in core/archipelago/src/api/rpc/lnd/wallet.rs — the seller-side/peer-file flow and the wallet UI's Receive flow
build_invoice_request_body(): one place where an invoice body is minted, with `private: true` unconditional so LND embeds route hints for unannounced channels
wallet
lightning
paid-content
added patterns
Two call sites that must agree get one shared constructor plus one test on the constructor, rather than two near-identical literals and a hope. The duplicated json! literal is exactly how one site got fixed and the other didn't.
created modified
core/archipelago/src/api/rpc/lnd/wallet.rs
`private: true` is unconditional rather than conditional on 'does this node have only private channels'. It is harmless when public channels exist — LND still routes directly over a public channel when it can, and the hint is an unused alternate path — so the conditional would add a failure mode (mis-detecting channel state) to buy nothing.
Both call sites route through one constructor so a single test pins the field for both, and neither can silently drift back to `false`.
FED-08
id description requirement verification human_judgment
D1 An invoice minted by the wallet UI's Receive flow embeds route hints for private/unannounced channels FED-08
kind ref status
unit core/archipelago/src/api/rpc/lnd/wallet.rs#invoice_request_body_always_sets_private_true pass
false
id description requirement verification human_judgment
D2 The seller-side/peer-file invoice path embeds them too — the twin site does not drift FED-08
kind ref status
other Both call sites (wallet.rs:330 and wallet.rs:554) call build_invoice_request_body; the json! literal exists in exactly one place pass
false
id description requirement verification human_judgment
D3 A payment actually arrives over a private channel on an affected node FED-08
kind ref status
manual_procedural Post-OTA checkpoint on the affected node (archy-x250-mad2) — NOT RUN; the plan forbids deploying directly to a user device, so this is verified after the release lands deferred
true
20min 2026-08-02 complete-pending-post-ota-checkpoint

Phase 1 Plan 19: Invoices Embed Route Hints for Private Channels (FED-08) Summary

A node whose inbound liquidity sits on unannounced channels could not be paid: its invoices carried no route hints, so a payer had no way to discover a path in. Both invoice-creation paths now mint their body through one constructor that sets private: true unconditionally.

Performance

  • Duration: ~20 min (code committed 2026-07-31 as e5c38866; this SUMMARY 2026-08-02)
  • Tasks: 1/2 (Task 2 is a post-OTA checkpoint on a user device — see below)
  • Files modified: 1

Accomplishments

  • build_invoice_request_body(amount_sats, memo) is now the single place an LND /v1/invoices body is constructed, with private: true set unconditionally and a doc comment explaining why it must stay that way.
  • Both call sites use it: the seller-side/peer-file flow (create_invoice) and the wallet UI's Receive flow (handle_lnd_createinvoice, the lnd.createinvoice RPC). The duplicated json! literal that let one site diverge from the other is gone.
  • invoice_request_body_always_sets_private_true pins the field for both sites at once.

Deviations from Plan

None.

Process note: as with 01-20, the code landed on 2026-07-31 (e5c38866) but no SUMMARY was written and the roadmap entry was never ticked, so the plan read as unstarted. This file closes that gap.

Known Stubs

None.

Threat Flags

None. private: true does not weaken anything: it adds a routing hint to an invoice the payer already holds. It does reveal the existence of an unannounced channel to whoever holds that specific invoice — which is inherent to being payable over that channel at all, and is the explicit intent of the requirement.

Outstanding: post-OTA checkpoint (Task 2)

The affected node is archy-x250-mad2, a user's device. Commit 516c3bfa records the standing constraint: never deploy directly to a user device — verify post-OTA instead. So the remaining verification is:

  1. Ship the release
  2. After it lands on the affected node, mint an invoice from the wallet's Receive flow
  3. Confirm the BOLT11 decodes with a route hint (r field) for the private channel
  4. Confirm a payment from outside actually settles over it

This is the one piece of FED-08 that cannot be proven from here.