One operator (lumosd, postgres) and ten clients
(waved, lwwallet on sqlite) on a regtest chain that only advances
when the harness mines. Every epoch runs 30 random client-to-client OOR
payments and one all-client refresh round, on top of everything prior epochs
created. The question is not how fast the stack is on a clean network, but
what the same payments and rounds cost once the operator's round history,
indexer and mailbox have real volume in them.
Wall clock per case, measured separately. Because state is never reset, an upward slope is the cost of accumulated history rather than run-to-run noise. The refresh number includes the harness-mined confirmation, so its floor is set by the round protocol, not the daemons.
Per-payment time from submitting the send to the OOR session reaching its terminal state, across the 30 sends of the epoch. Sends run ten at a time (every client sends at once), so the spread between the median and the slowest send is the contention signal.
Per-client time from queueing the refresh to that client's round reaching a terminal state, all ten clients in the same round. The median and the slowest client should track each other; a widening gap means some clients wait on work the round does per participant. A client whose quoted refresh fee would leave too little residual value refuses to join ("insufficient_residual"): those fee-quote rejections count in the epoch detail as their own bucket, not as failures, and are excluded from the timing percentiles.
Three views of the system's money. Deployed is the
operator ledger's deployed_capital: every sat locked in
unexpired on-chain batch outputs, including the operator's own refresh
liquidity and fully-forfeited history the sweeper has not reclaimed yet.
User spendable is the sum of all ten clients' confirmed offchain
balances. Live vtxo value is the operator indexer's total for
live vtxos, an independent measurement that should track user spendable
exactly. The gap between deployed and the other two is capital the
operator has committed beyond what users can spend; batch expiry (1008
blocks after a round confirms) is when the sweeper starts winning it
back.
Deployed capital divided by user-spendable capital: how much the operator has locked on chain to give users one spendable sat. Every refresh round adds newly-committed outputs while the forfeited batch stays locked until its expiry, so this ratio is expected to climb between sweeps and fall when the sweeper reclaims expired batches. A ratio that only ever climbs means reclamation is not keeping up.
Every sat in the system entered through a harness-made
boarding deposit, so total-deposited is known exactly, and
conservation residual = deposited − user spendable −
pending − operator fees must be zero: any other non-null value
means sats appeared or vanished somewhere in the stack. claims
residual cross-checks the operator ledger's own
user_vtxo_claims liability against what clients report; as
wired it trails by exactly the cumulative refresh fees, so it tracking
the fee line is the known baseline and a departure from that is the
signal. Epochs before this was measured render as gaps.
Total size postgres reports for the lumos database.
Postgres carries a fixed multi-megabyte catalog baseline: read the slope, not
the offset. The largest tables behind this number are in the
snapshot.
Marginal cost of one epoch's work: the operator's postgres growth against the summed sqlite growth of all ten clients (main files plus WAL). Flat means the cost per unit of work is holding; a rising line means each epoch stores more than the last for the same 30 payments and one round.
Summed sqlite footprint of all ten clients, and
wb-client01 alone as the representative client (clients are
symmetric by construction). Includes each database's WAL, so a stalled
checkpoint shows up here as growth the main file never sees.
Resident set sampled once after the epoch's cases finish, so it
is where memory settles rather than a peak during the run. The high water
mark is memory.peak from the container's cgroup: it cannot be
reset without root, so it only ever rises, and a mark that keeps climbing
epoch after epoch is the leak signal.
Same measurements on the observed client. One client stands for all ten: they run the same binary against the same operator with the same workload shape.
Live goroutine count on the operator and the observed client at the end of each epoch. A count that grows with the series and never settles is a leaked-goroutine signal; growth proportional to load that returns to a floor is normal.