mirror of
https://github.com/lightningnetwork/lnd.git
synced 2026-08-17 13:06:14 +02:00
In this commit, we add findings sections 21 through 23: the foreign balance sheet (exp-029, the ordering survives on balances nobody fit to and the circularity caveat measures out to zero), the misattribution mechanism (exp-030, only settlements prove innocence, the quarantine keeps), and the closing of the compose world (exp-031, both escapes failed, the evolution track at its measured boundary). The index now names the release-candidate pair and states the two-track split: evolution found the paradigm, engineering is shipping it.
659 lines
33 KiB
HTML
659 lines
33 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<title>Evolving Lightning's next routing algorithm — lnd × GEPA</title>
|
||
<meta name="description" content="An LLM-driven evolutionary search over Lightning routing algorithms, run against lnd's real pathfinding stack in an in-process payment simulator. What it found, and how." />
|
||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||
<link href="https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,300..600;1,6..72,300..500&family=Spline+Sans+Mono:wght@400;500&display=swap" rel="stylesheet" />
|
||
<link rel="stylesheet" href="style.css" />
|
||
</head>
|
||
<body>
|
||
|
||
<a class="skip" href="#main">Skip to content</a>
|
||
|
||
<header class="site-header">
|
||
<div class="shell">
|
||
<a class="wordmark" href="index.html">lnd<span class="x">×</span>GEPA</a>
|
||
<nav class="site-nav">
|
||
<a href="index.html" aria-current="page">overview</a>
|
||
<a href="findings.html">findings</a>
|
||
<a href="drift.html">drift</a>
|
||
<a href="#run">live run</a>
|
||
</nav>
|
||
</div>
|
||
</header>
|
||
|
||
<main id="main">
|
||
|
||
<!-- ================= MASTHEAD ================= -->
|
||
<div class="shell masthead">
|
||
<div class="eyebrow">
|
||
Research log<span class="sep">/</span>Lightning Network pathfinding<span class="sep">/</span>July 2026
|
||
</div>
|
||
<h1>Evolving Lightning's <em>next</em> routing algorithm</h1>
|
||
<div class="masthead-grid">
|
||
<p class="standfirst">
|
||
We pointed an LLM-driven evolutionary search at lnd's real pathfinding
|
||
stack, inside a simulator that hides channel liquidity the way the network
|
||
does. <strong>Tuning its parameters found nothing. Replacing the algorithm
|
||
found a lot.</strong>
|
||
</p>
|
||
<div class="glance">
|
||
<div class="g hi">
|
||
<span class="l">attempts per payment<br>mainnet, vs lnd's 19.8</span>
|
||
<span class="v">2.3</span>
|
||
</div>
|
||
<div class="g">
|
||
<span class="l">objective, mainnet<br>vs lnd's 0.694</span>
|
||
<span class="v">0.791</span>
|
||
</div>
|
||
<div class="g">
|
||
<span class="l">evolved lines of Go<br>from a 300-line seed</span>
|
||
<span class="v">1,525</span>
|
||
</div>
|
||
<div class="g hi">
|
||
<span class="l">tiers the integrated branch leads<br>stock lnd, zero losses</span>
|
||
<span class="v">14 / 14</span>
|
||
</div>
|
||
<div class="cap">best evolved routers (mx_c3/hb1) against lnd's production stack; the last row is the interval-router branch measured inside lnd's own payment lifecycle (exp-027)</div>
|
||
</div>
|
||
</div>
|
||
<div class="byline">
|
||
<span>method <b>GEPA reflective evolution</b></span>
|
||
<span>reflection LM <b>gpt-5.6-sol</b></span>
|
||
<span>evaluator <b>cmd/routesim</b></span>
|
||
<span>experiments <b>exp-001 … exp-031</b></span>
|
||
<span>champions <b>hb1 + mx_c3</b>, unchanged since exp-007 · specialists atomic1 + econ2</span>
|
||
<span>shipping <b>interval-lnd, 14/14 over stock lnd</b> · release candidate <b>eb4fc3e62</b>, rebased <b>b489649f6</b> on the fork</span>
|
||
<span>tracks <b>evolution at its measured boundary</b> (exp-031) · <b>the ship track owns the frontier</b> · replay on real payment history next week</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ================= 01 · FINDINGS ================= -->
|
||
<section id="result">
|
||
<div class="shell">
|
||
<div class="sec-head">
|
||
<div class="sec-no">01</div>
|
||
<h2>What the search found</h2>
|
||
<p class="sec-sub">
|
||
Every number below is held out. The closing check ran on a real mainnet
|
||
graph snapshot — lnd's home turf, and a topology the evolved routers had
|
||
never seen.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="keyrow wide">
|
||
<div class="key hi">
|
||
<span class="kn">8.6<span class="u">×</span></span>
|
||
<div class="kl">
|
||
fewer HTLC attempts per payment than lnd on the real mainnet graph, at
|
||
the same success rate, on a perfect failure channel
|
||
</div>
|
||
<div class="kf">2.3 vs 19.8 attempts · exp-009 · ratio retired by exp-019: under realistic attribution degradation the edge converts to success</div>
|
||
</div>
|
||
<div class="key">
|
||
<span class="kn">6<span class="u">of 6</span></span>
|
||
<div class="kl">
|
||
held-out tiers the evolved routers lead: sealed synthetic test,
|
||
out-of-distribution topologies, mainnet snapshot, drifting liquidity,
|
||
splitting pressure, and the atomic arena
|
||
</div>
|
||
<div class="kf">nine challengers have since failed to displace them — though the frontier is now three regimes deep: hb1/mx_c3 where information wins, atomic1 where holds contend, econ2 where money is scarce</div>
|
||
</div>
|
||
<div class="key">
|
||
<span class="kn">0</span>
|
||
<div class="kl">
|
||
parameter settings, out of 400 evaluations of estimator and cost
|
||
knobs, that beat the lnd defaults
|
||
</div>
|
||
<div class="kf">exp-002 · the negative result that redirected the project</div>
|
||
</div>
|
||
</div>
|
||
|
||
<figure>
|
||
<div class="fig-head">
|
||
<span class="fig-t">Attempts per payment on a mainnet snapshot</span>
|
||
<span class="fig-n">Fig. 1 · lower is better</span>
|
||
</div>
|
||
<div class="plot resp" id="fig-attempts"></div>
|
||
<figcaption>
|
||
12,161 nodes, 39,659 channels, 100 payments from the network's
|
||
highest-degree node. Success rates are close — lnd 0.790, seed 0.820,
|
||
evolved 0.810 — so the whole difference lands in <b>how much probing it
|
||
takes to get there</b>. This is the tier lnd should win: its defaults were
|
||
tuned for this graph, while the evolved routers were bred entirely on
|
||
synthetic topologies. The attempt ratio is a perfect-channel figure;
|
||
exp-019 retired it, and under a degraded failure channel the same edge
|
||
shows up as success instead
|
||
(<a class="link" href="findings.html#attribution">the ladder</a>).
|
||
</figcaption>
|
||
</figure>
|
||
|
||
<figure>
|
||
<div class="fig-head">
|
||
<span class="fig-t">Composite objective, by router and held-out tier</span>
|
||
<span class="fig-n">Fig. 2 · higher is better</span>
|
||
</div>
|
||
<div class="plot resp" id="fig-champions"></div>
|
||
<div class="legend">
|
||
<span class="item"><i style="background:#a83f22"></i> evolved by GEPA</span>
|
||
<span class="item"><i style="background:#8a8175"></i> baseline (lnd, or hand-written)</span>
|
||
</div>
|
||
<figcaption>
|
||
Objective is <span class="mono">success − 0.01·min(extra attempts, 15) −
|
||
0.00002·min(fee ppm, 5000)</span>. The two evolved routers lead on all
|
||
three tiers. On synthetic corpora the gap is mostly success rate; on the
|
||
real graph it is almost entirely efficiency. Reruns are bit-identical
|
||
(stdev 0.00000 over five repeats), and both champions were audited clean
|
||
of simulator exploits.
|
||
</figcaption>
|
||
<details class="tableview">
|
||
<summary>Table view</summary>
|
||
<div class="tw">
|
||
<table class="data">
|
||
<caption>Composite objective. Combined is the mean of the two synthetic held-out sets.</caption>
|
||
<thead>
|
||
<tr>
|
||
<th>router</th>
|
||
<th class="num">mainnet</th>
|
||
<th class="num">hard sealed test</th>
|
||
<th class="num">out-of-distribution</th>
|
||
<th class="num">combined</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>lnd production stack<span class="sub">Dijkstra + mission control</span></td>
|
||
<td class="num" data-l="mainnet">0.694</td><td class="num" data-l="hard sealed test">0.309</td>
|
||
<td class="num" data-l="out-of-distribution">0.357</td><td class="num" data-l="combined">0.333</td>
|
||
</tr>
|
||
<tr>
|
||
<td>hand-written seed<span class="sub">~300 lines, cheapest path + blacklist</span></td>
|
||
<td class="num" data-l="mainnet">0.762</td><td class="num" data-l="hard sealed test">0.530</td>
|
||
<td class="num" data-l="out-of-distribution">0.487</td><td class="num" data-l="combined">0.509</td>
|
||
</tr>
|
||
<tr>
|
||
<td>hb1<span class="sub">evolved, 872 lines</span></td>
|
||
<td class="num" data-l="mainnet">0.790</td><td class="num" data-l="hard sealed test">0.586</td>
|
||
<td class="num" data-l="out-of-distribution">0.545</td><td class="num" data-l="combined">0.565</td>
|
||
</tr>
|
||
<tr class="best">
|
||
<td>mx_c3<span class="sub">evolved, 1,525 lines</span></td>
|
||
<td class="num" data-l="mainnet">0.791</td><td class="num" data-l="hard sealed test">0.583</td>
|
||
<td class="num" data-l="out-of-distribution">0.581</td><td class="num" data-l="combined">0.582</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</details>
|
||
</figure>
|
||
|
||
<div class="prose">
|
||
<p>
|
||
The headline is not the size of the win, it is <em>where the win came
|
||
from</em>. A 400-evaluation search over lnd's own pathfinding knobs — which
|
||
probability estimator, how much a failed attempt should virtually cost, the
|
||
floor on acceptable route probability — produced no setting that beat the
|
||
shipped defaults on validation. The defaults are locally robust; the
|
||
headroom is not in the knobs.
|
||
</p>
|
||
<p>
|
||
Meanwhile a deliberately naive 300-line router with a <em>different
|
||
paradigm</em> beat lnd's full production stack by 39% on the objective,
|
||
winning or tying every example. Handing that seed to the optimizer, and
|
||
letting it rewrite the whole algorithm rather than adjust its settings,
|
||
produced routers that beat both. What they invented — liquidity intervals
|
||
instead of decaying penalties — is the interesting part.
|
||
</p>
|
||
<p>
|
||
<a class="link" href="findings.html">Read the full findings →</a>
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ================= 02 · METHOD ================= -->
|
||
<section id="method">
|
||
<div class="shell">
|
||
<div class="sec-head">
|
||
<div class="sec-no">02</div>
|
||
<h2>How the search works</h2>
|
||
<p class="sec-sub">
|
||
A candidate is a whole routing algorithm in Go. Every proposal is
|
||
compiled into a simulator and made to actually pay.
|
||
</p>
|
||
</div>
|
||
|
||
<figure>
|
||
<div class="fig-head">
|
||
<span class="fig-t">One turn of the evolutionary loop</span>
|
||
<span class="fig-n">Fig. 3</span>
|
||
</div>
|
||
<div class="schema">
|
||
<svg viewBox="0 0 1000 252" role="img" aria-label="The GEPA loop: propose, compile, simulate, score, reflect, then back to propose.">
|
||
<!-- stage boxes -->
|
||
<g>
|
||
<rect x="1" y="26" width="170" height="92" fill="#fbfaf6" stroke="#cbc4b2" stroke-width="1"/>
|
||
<text class="s-num" x="14" y="46">01</text>
|
||
<text class="s-title" x="14" y="66" font-size="14">propose</text>
|
||
<text class="s-body" x="14" y="86">the reflection LM</text>
|
||
<text class="s-body" x="14" y="102">rewrites the router</text>
|
||
</g>
|
||
<path d="M 179 72 h 20 m -6 -5 l 6 5 l -6 5" fill="none" stroke="#b3ab97" stroke-width="1.2"/>
|
||
<g>
|
||
<rect x="207" y="26" width="170" height="92" fill="#fbfaf6" stroke="#cbc4b2" stroke-width="1"/>
|
||
<text class="s-num" x="220" y="46">02</text>
|
||
<text class="s-title" x="220" y="66" font-size="14">compile</text>
|
||
<text class="s-body" x="220" y="86">go build −overlay drops</text>
|
||
<text class="s-body" x="220" y="102">it into the simulator</text>
|
||
</g>
|
||
<path d="M 385 72 h 20 m -6 -5 l 6 5 l -6 5" fill="none" stroke="#b3ab97" stroke-width="1.2"/>
|
||
<g>
|
||
<rect x="413" y="26" width="170" height="92" fill="#fbfaf6" stroke="#cbc4b2" stroke-width="1"/>
|
||
<text class="s-num" x="426" y="46">03</text>
|
||
<text class="s-title" x="426" y="66" font-size="14">simulate</text>
|
||
<text class="s-body" x="426" y="86">it pays, against hidden</text>
|
||
<text class="s-body" x="426" y="102">channel liquidity</text>
|
||
</g>
|
||
<path d="M 591 72 h 20 m -6 -5 l 6 5 l -6 5" fill="none" stroke="#b3ab97" stroke-width="1.2"/>
|
||
<g>
|
||
<rect x="619" y="26" width="170" height="92" fill="#fbfaf6" stroke="#cbc4b2" stroke-width="1"/>
|
||
<text class="s-num" x="632" y="46">04</text>
|
||
<text class="s-title" x="632" y="66" font-size="14">score</text>
|
||
<text class="s-body" x="632" y="86">success, minus attempt</text>
|
||
<text class="s-body" x="632" y="102">and fee penalties</text>
|
||
</g>
|
||
<path d="M 797 72 h 20 m -6 -5 l 6 5 l -6 5" fill="none" stroke="#b3ab97" stroke-width="1.2"/>
|
||
<g>
|
||
<rect x="825" y="26" width="170" height="92" fill="#fbfaf6" stroke="#cbc4b2" stroke-width="1"/>
|
||
<text class="s-num" x="838" y="46">05</text>
|
||
<text class="s-title" x="838" y="66" font-size="14">reflect</text>
|
||
<text class="s-body" x="838" y="86">keep it only if it holds</text>
|
||
<text class="s-body" x="838" y="102">up across the splits</text>
|
||
</g>
|
||
|
||
<!-- feedback return path -->
|
||
<path d="M 910 118 V 176 H 86 V 124 m -5 6 l 5 -6 l 5 6"
|
||
fill="none" stroke="#a83f22" stroke-width="1.4"/>
|
||
<text class="s-label-strong" x="498" y="199" text-anchor="middle" fill="#a83f22">
|
||
per-attempt failure traces are the feedback
|
||
</text>
|
||
<text class="s-body" x="498" y="220" text-anchor="middle">
|
||
which hop died, at what amount, with which BOLT error — so the next mutation is informed, not random
|
||
</text>
|
||
</svg>
|
||
</div>
|
||
<div class="scrollhint">scroll the diagram sideways →</div>
|
||
<figcaption>
|
||
The optimizer never sees hidden balances. A candidate gets the public
|
||
gossip graph, its own channel balances, and the errors its attempts
|
||
provoke — the same information a real Lightning sender has.
|
||
</figcaption>
|
||
</figure>
|
||
|
||
<div class="prose">
|
||
<h3>The simulator runs lnd's real code</h3>
|
||
<p>
|
||
<code>routing/sim_graph.go</code> is an in-memory Lightning network with
|
||
hidden per-channel balances and per-direction policies: base and
|
||
proportional fees, CLTV deltas, min and max HTLC. It implements lnd's own
|
||
<code>Graph</code> interface, so lnd's production pathfinding and mission
|
||
control run against it unmodified — which is what makes the baseline
|
||
honest.
|
||
</p>
|
||
<p>
|
||
Forwarding enforces real BOLT semantics. An attempt that asks too little
|
||
fee gets <code>FeeInsufficient</code>; one that asks for more than a hop
|
||
holds gets <code>TemporaryChannelFailure</code>, the liquidity miss that
|
||
all of routing is really about. Balances move on success and unwind on
|
||
failure. Topologies are synthetic (line, grid, hub-and-spoke, small-world,
|
||
scale-free) or loaded from a mainnet <code>describegraph</code> snapshot,
|
||
and hidden balances follow a half, uniform, or <em>bimodal</em> model — the
|
||
last one hugging one end of each channel, which is both realistic and the
|
||
hard case.
|
||
</p>
|
||
<p>
|
||
It is fast enough to be an inner loop: ten payments on a 200-node network
|
||
in about 0.3 seconds including process startup, so thousands of
|
||
evaluations are cheap.
|
||
</p>
|
||
|
||
<h3>A candidate is an algorithm, not a config</h3>
|
||
<p>
|
||
The evolvable unit is a Go file behind a paradigm-free interface: gossip
|
||
view, local balances, and per-attempt feedback in; a route out. GEPA
|
||
rewrites that file, <code>go build -overlay</code> compiles the rewrite into
|
||
the simulator, and the evaluator scores it on a corpus split into train,
|
||
validation and sealed test. Nothing in the contract mentions Dijkstra,
|
||
mission control, or probability estimators. Those become background
|
||
knowledge the reflection prompt may draw on, keep, reshape, or discard.
|
||
</p>
|
||
|
||
<div class="note">
|
||
<h4>the sandbox held</h4>
|
||
<p>
|
||
An independent audit found that the graph session handed candidates the
|
||
concrete simulator graph, type-assertable back into a read of hidden
|
||
balances or an outright rewrite of ground-truth liquidity — a
|
||
perfect-score reward hack using no banned identifiers. It was sealed the
|
||
same day, and every in-flight candidate was checked against it: zero
|
||
hits. No result on this site was produced through that hole.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ================= 03 · CORPUS ================= -->
|
||
<section id="corpus">
|
||
<div class="shell">
|
||
<div class="sec-head">
|
||
<div class="sec-no">03</div>
|
||
<h2>The scenarios it is scored against</h2>
|
||
<p class="sec-sub">
|
||
<span class="mono" id="c-files">—</span> scenario files,
|
||
<span class="mono" id="c-scen">—</span> payments,
|
||
split <span class="mono" id="c-split">—</span>. Validation picks the
|
||
incumbent; the test split stays sealed until a champion is declared.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="figgrid">
|
||
<figure>
|
||
<div class="fig-head">
|
||
<span class="fig-t">Topology</span>
|
||
<span class="fig-n">files</span>
|
||
</div>
|
||
<div class="bars" id="bars-topology"></div>
|
||
</figure>
|
||
<figure>
|
||
<div class="fig-head">
|
||
<span class="fig-t">Hidden liquidity model</span>
|
||
<span class="fig-n">files</span>
|
||
</div>
|
||
<div class="bars" id="bars-liquidity"></div>
|
||
<figcaption>
|
||
Bimodal is the hard regime: funds parked at one end of each channel,
|
||
so capacity tells you almost nothing about what will actually pass.
|
||
</figcaption>
|
||
</figure>
|
||
<figure>
|
||
<div class="fig-head">
|
||
<span class="fig-t">Payment amount</span>
|
||
<span class="fig-n">scenarios, satoshis</span>
|
||
</div>
|
||
<div class="bars" id="bars-amount"></div>
|
||
</figure>
|
||
<figure>
|
||
<div class="fig-head">
|
||
<span class="fig-t">Shard budget</span>
|
||
<span class="fig-n">scenarios, max parts</span>
|
||
</div>
|
||
<div class="bars" id="bars-parts"></div>
|
||
</figure>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ================= 04 · LIVE RUN ================= -->
|
||
<section id="run">
|
||
<div class="shell">
|
||
<div class="sec-head">
|
||
<div class="sec-no">04</div>
|
||
<h2>Run telemetry (latest completed optimizer run)</h2>
|
||
<p class="sec-sub">
|
||
Telemetry from the optimizer, exported straight out of the GEPA run
|
||
directory. <span class="mono">code_drift1</span> has since finished all 400
|
||
evaluations, and so have exp-010's three splitting arms — all of them beaten
|
||
by the champions
|
||
(<a class="link" href="findings.html#splitting">the verdict</a>). exp-010b's
|
||
two atomic-arena arms have since closed the same way — the champion's fifth
|
||
hold, against an arena built to charge its probe ladder honestly
|
||
(<a class="link" href="findings.html#atomic">the atomic verdict</a>) — and so
|
||
has exp-012, which found no hot-cache regime anywhere but did find the one
|
||
change this work argues for upstream
|
||
(<a class="link" href="findings.html#coldcache">cold cache, hot load</a>).
|
||
Nothing is live now. The telemetry below is still
|
||
<span class="mono">exp-018</span>'s gepa arm, the engine adjudication, which
|
||
gave three optimizers the same seed, corpus and eval budget and found that
|
||
only gepa produced a router at all
|
||
(<a class="link" href="findings.html#omni">the adjudication</a>). Two
|
||
optimizer runs have finished since, both overnight and both closed:
|
||
<span class="mono">exp-022</span> bred a router against a channel that lies
|
||
about which hop failed
|
||
(<a class="link" href="findings.html#lying">the lying channel</a>), and
|
||
<span class="mono">exp-024</span> gave the runner-up engine ten times the
|
||
evaluations to see whether the band was ever budget starvation
|
||
(<a class="link" href="findings.html#ceilingarm">the ceiling arm</a>). In
|
||
between, exp-021 turned the findings into a flag-gated diff against lnd's own
|
||
stack, where one mechanism is now PR-ready and the other is a measured null
|
||
(<a class="link" href="findings.html#distillation">the distillation patch</a>).
|
||
The most recent run of all is <span class="mono">exp-025</span>, the first
|
||
bred in a world where money is real, and its winner is the first router here
|
||
ever to read the fee budget it is handed
|
||
(<a class="link" href="findings.html#econevo">evolution learns to count</a>).
|
||
Two runs have closed since: the compose world, every economic knob plus the
|
||
lying channel at once, which returned its seed unchanged, and
|
||
<span class="mono">exp-028</span>, its first pre-registered escape, which
|
||
seeded the same world from the fee-budget specialist and reproduced the
|
||
give-up attractor from a second lineage
|
||
(<a class="link" href="findings.html#compose">the rule</a>). The 800-evaluation
|
||
arm, <span class="mono">code_full3</span>, is live and carries what is left of
|
||
the compose question.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="note">
|
||
<h4>where the program stands</h4>
|
||
<p>
|
||
<strong>No optimizer run is live.</strong> Champions are unchanged at hb1
|
||
and mx_c3, nine challengers deep, and the arms still open are about
|
||
changing the environment rather than changing the search
|
||
(<a class="link" href="findings.html#ceilingarm">§15</a> is why).
|
||
</p>
|
||
<p>
|
||
<em>(Update, 30 July: the frontier is unchanged and the ledger still reads
|
||
nine challengers. Champions hb1 and mx_c3, specialists atomic1 where holds
|
||
contend and econ2 where money is scarce. What has changed is where the work
|
||
points: the integration branch now measures at
|
||
<strong>14 of 14 tiers interval-solid over stock lnd with zero losses</strong>,
|
||
margins intact under the production default fee limit
|
||
(<a class="link" href="findings.html#integration">§19</a>), and the stated
|
||
target is shipping it in the next lnd major release. One optimizer run is
|
||
live, the 800-evaluation compose arm
|
||
<span class="mono">code_full3</span>.)</em>
|
||
</p>
|
||
<p>
|
||
<em>(Update, 31 July: <span class="mono">code_full3</span> has closed, and
|
||
with it the evolution track's search for new machinery here. 800 evaluations
|
||
returned the hand seed to seven digits, which fails the second of the two
|
||
pre-registered escapes and makes the compose world closed to this recipe at
|
||
any seed and any practical budget
|
||
(<a class="link" href="findings.html#closed">§23</a>). Nothing is live; no run
|
||
holds the router. The frontier now belongs to the ship track. The release
|
||
candidate is <span class="mono">interval-router</span> at
|
||
<span class="mono">eb4fc3e62</span>, rebased as
|
||
<span class="mono">b489649f6</span> on the fork, and it has been validated
|
||
twice more since: champion-grade to the third decimal on a liquidity family
|
||
nobody here authored
|
||
(<a class="link" href="findings.html#foreign">§21</a>), and carrying a fix for
|
||
the one interaction §19 could not explain, where shifted blame fabricates an
|
||
alibi for the guilty channel
|
||
(<a class="link" href="findings.html#innocence">§22</a>). Champions unchanged,
|
||
ledger still nine challengers deep. Next is offline replay on a real node's
|
||
payment history, which is the last escape from "simulator-shaped" this program
|
||
has left.)</em>
|
||
</p>
|
||
<p>
|
||
<strong>exp-023 and exp-025, economic realism, both closed.</strong> All
|
||
five stages are merged and flag-gated — min and max HTLC pressure, inbound
|
||
fees, fees as a first-class cost, concurrent payments, latency — each proven
|
||
byte-identical with its flag off. The 1,920-run sweep says the champions'
|
||
edge is informational rather than a pricing edge
|
||
(<a class="link" href="findings.html#econ">the priced world</a>), and the
|
||
evolution run that followed produced econ2, the fee-budget specialist and
|
||
challenger number nine
|
||
(<a class="link" href="findings.html#econevo">evolution learns to count</a>).
|
||
The compose-world run (all five economic knobs plus the lying channel) is live as code_full1; its five knobs are
|
||
live at once. <em>(It has since closed, returning its seed unchanged, and so
|
||
has the first of its two escapes
|
||
(<a class="link" href="findings.html#compose">§20</a>); the second is live
|
||
now.)</em>
|
||
</p>
|
||
<p>
|
||
<strong>The interval-router branch.</strong> Separately from the simulator,
|
||
the champions' paradigm is being ported into lnd proper: fourteen commits on
|
||
<span class="mono">interval-router</span>, unchanged through both economic
|
||
cycles, that put a liquidity interval per directed channel behind
|
||
<span class="mono">routerrpc.router=interval</span>, off by default, with
|
||
the stock stack untouched when the flag is unset. <strong>It still has not
|
||
been benchmarked in this simulator.</strong> Nothing on this site is a
|
||
measurement of that branch, and no number here should be read as one — though
|
||
the hybrid it builds, evolved beliefs on top of lnd's own fee-aware pricing,
|
||
is exactly what <a class="link" href="findings.html#econ">§17</a> says to
|
||
build. <em>(That benchmark has since run, and this paragraph is
|
||
the one thing on the page it retires: exp-027 put the branch inside lnd's
|
||
real payment lifecycle and measured it over fourteen tiers, where it scores
|
||
0.788 on mainnet against stock lnd's 0.694 and leads stock lnd on all
|
||
fourteen with zero losses
|
||
(<a class="link" href="findings.html#integration">§19</a>). The hybrid
|
||
§17 asked for is built, measured, and the thing we intend to
|
||
ship.)</em>
|
||
</p>
|
||
</div>
|
||
|
||
<div class="runbar">
|
||
<span><span class="dot"></span>run <b id="rb-run">—</b></span>
|
||
<span>reflection <b id="rb-lm">—</b></span>
|
||
<span>mode <b id="rb-mode">—</b></span>
|
||
<span>budget <b>150 evals</b></span>
|
||
</div>
|
||
|
||
<div class="statline wide" id="run-stats"></div>
|
||
|
||
<div class="prose" style="margin-bottom:34px">
|
||
<p>
|
||
<code>code_drift1</code> was the first run in a moving world. Its
|
||
predecessor, <code>code_gen2</code>, showed that more evaluations of a
|
||
static environment buy nothing — three independently bred routers landed
|
||
inside a band 0.014 wide (the
|
||
<a class="link" href="findings.html#ceiling">paradigm ceiling</a>). So this
|
||
run changed the environment instead of the budget: a virtual clock and
|
||
background senders moving hidden liquidity between our payments, and the
|
||
question of whether time-awareness re-evolves once knowledge genuinely goes
|
||
stale. <strong>It did — and it still lost.</strong> The winner stamps every
|
||
belief and halves its confidence every 35 virtual minutes, and the time-less
|
||
champions beat it on all four held-out tiers, drift included. The mechanism,
|
||
the numbers and the caveats are on the
|
||
<a class="link" href="drift.html">drift page</a>.
|
||
</p>
|
||
</div>
|
||
|
||
<figure class="wide" style="margin-top:0">
|
||
<div class="fig-head">
|
||
<span class="fig-t">Score over iterations</span>
|
||
<span class="fig-n">Fig. 4 · minibatch objective</span>
|
||
</div>
|
||
<div class="plot" id="score-chart"></div>
|
||
<div class="scrollhint">scroll the chart sideways →</div>
|
||
<div class="legend">
|
||
<span class="item"><i class="line" style="background:#a83f22"></i> best kept</span>
|
||
<span class="item"><i class="line" style="background:#2f6ea8"></i> proposed</span>
|
||
<span class="item"><i class="dash"></i> seed baseline</span>
|
||
</div>
|
||
<figcaption>
|
||
These are per-minibatch scores on the training split, not held-out
|
||
numbers — they are how GEPA decides what to keep, and they run
|
||
optimistically high. Every comparison in section 01 comes from separate
|
||
held-out runs instead.
|
||
</figcaption>
|
||
</figure>
|
||
|
||
<figure class="wide">
|
||
<div class="fig-head">
|
||
<span class="fig-t">Candidate lineage</span>
|
||
<span class="fig-n">Fig. 5 · select a candidate</span>
|
||
</div>
|
||
<div class="plot dag" id="lineage-dag"></div>
|
||
<figcaption>
|
||
Each node is one compiled, scored router. Accepted candidates stay on the
|
||
frontier and can be mutated further; rejects are dead ends. The scores are
|
||
per-minibatch and each is measured on a different subset, so a rejected
|
||
candidate can carry a higher number than the incumbent without being
|
||
better.
|
||
</figcaption>
|
||
</figure>
|
||
|
||
<div class="panels">
|
||
<div class="panel">
|
||
<div class="fig-head">
|
||
<span class="fig-t">Candidate detail</span>
|
||
<span class="fig-n" id="detail-sub">—</span>
|
||
</div>
|
||
<div id="cand-detail"></div>
|
||
</div>
|
||
<div class="panel">
|
||
<div class="fig-head">
|
||
<span class="fig-t">What the mutation changed</span>
|
||
<span class="fig-n">line diff</span>
|
||
</div>
|
||
<div class="selects">
|
||
<label>base <select id="diff-a"></select></label>
|
||
<span>→</span>
|
||
<label>candidate <select id="diff-b"></select></label>
|
||
</div>
|
||
<pre class="diff" id="diff-view"></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<div class="shell">
|
||
<div class="readnext">
|
||
<div class="k">read next</div>
|
||
<a class="big" href="findings.html">Findings: what the evolved routers kept, dropped, and invented</a>
|
||
<p>
|
||
The definitive write-up — the paradigm result, the champion scores, an
|
||
anatomy of the evolved algorithms against lnd's, the ceiling three separate
|
||
lineages ran into, what happens when a router is handed knowledge it did not
|
||
pay for, the one patch that came out of all this and the theory that died
|
||
beside it
|
||
(<a class="link" href="findings.html#distillation">the distillation patch</a>),
|
||
what a second optimizer does with ten times the budget
|
||
(<a class="link" href="findings.html#ceilingarm">the ceiling arm</a>), what a
|
||
router bred against a channel that lies buys its robustness with
|
||
(<a class="link" href="findings.html#lying">the lying channel</a>), what
|
||
happens to all of it once the world has prices
|
||
(<a class="link" href="findings.html#econ">the priced world</a> and
|
||
<a class="link" href="findings.html#econevo">evolution learns to count</a>),
|
||
what happens when the whole evolved belief system is put inside lnd's own
|
||
payment lifecycle and measured there
|
||
(<a class="link" href="findings.html#integration">the integration benchmark</a>),
|
||
what happens to the whole ordering on a balance sheet nobody here drew
|
||
(<a class="link" href="findings.html#foreign">the foreign balance sheet</a>),
|
||
the one unexplained interaction on the release candidate's record and the trust
|
||
boundary that closed it
|
||
(<a class="link" href="findings.html#innocence">misattribution manufactures innocence</a>),
|
||
where the evolution track finally ran out of room
|
||
(<a class="link" href="findings.html#closed">the compose world is closed</a>),
|
||
the corrections we have had to make to our own record, and the process lessons
|
||
from thirty-one experiments.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
</main>
|
||
|
||
<div class="shell">
|
||
<footer class="site-footer">
|
||
<span>lnd × GEPA — Lightning routing evolution</span>
|
||
<span id="foot-run">run data loading…</span>
|
||
</footer>
|
||
</div>
|
||
|
||
<script src="app.js"></script>
|
||
</body>
|
||
</html>
|