mirror of
https://github.com/lightningnetwork/lnd.git
synced 2026-08-17 13:06:14 +02:00
In this commit, we write up exp-010b on the findings page as a new section 07, "The honest arena: atomic commitment, and the fifth challenge", with the process and timeline sections renumbered to 08 and 09 behind it. The section tells the arena story first: shards that hold liquidity until the whole payment settles, siblings contending for what is held, and background traffic drifting on every attempt boundary, so a long reactive ladder finally pays for the churn it sits through. Flag-off byte-identity means none of the earlier results on the page moved. The headline is the baseline, which reordered the field before evolution ran at all: lnd falls from second place to last, spending 105 attempts per payment where it spent 23 with instant settlement, and exp-010's persistent-plan router pulls statistically even with mx_c3 on both atomic tiers without ever having seen an atomic shard. Two tables carry the numbers, the seven-router baseline and the six-tier paired sweep with sign-test deltas against the champion. Then the verdicts. mx_c3 survives its fifth direct challenge on an arena built expressly against its evidence ladder, but the shape of the frontier changed: the codex arm's hybrid of cross-payment memory and reservation-ledger planning is the first challenger in the program with no collapse tier, and it routes mainnet payments in 1.6 attempts, the lowest figure we have measured. The Opus arm lost outright, its drift-bred bound relaxation burning 57 attempts per payment, which flips the exp-010 proposer A/B and adds the clause that proposer strength interacts with environment variance. We also close the forward pointers. The exp-010 sidenote now says how its designed follow-up turned out, the drift page's "one drift intensity" caveat gets the attempt-boundary answer, and the index byline and live-run panel move to exp-010b closed with exp-012 next.
725 lines
35 KiB
HTML
725 lines
35 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<title>Drift — the environment strikes back (exp-008)</title>
|
||
<meta name="description" content="The simulator gets a virtual clock and background traffic, so knowledge genuinely goes stale. Time-awareness re-evolved — a 35-minute confidence half-life and hard bounds that expire at twenty — and the time-less champions still won every tier, drift included." />
|
||
<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">overview</a>
|
||
<a href="findings.html">findings</a>
|
||
<a href="drift.html" aria-current="page">drift</a>
|
||
<a href="index.html#run">live run</a>
|
||
</nav>
|
||
</div>
|
||
</header>
|
||
|
||
<main id="main">
|
||
|
||
<!-- ================= MASTHEAD ================= -->
|
||
<div class="shell masthead">
|
||
<div class="eyebrow">
|
||
Verdict in<span class="sep">/</span>exp-008<span class="sep">/</span>25 July 2026
|
||
</div>
|
||
<h1>The environment <em>strikes back</em></h1>
|
||
<p class="standfirst">
|
||
The evolved champions carry no clock, and we always suspected that was partly
|
||
our simulator's fault: hidden liquidity only moved when our own payments moved
|
||
it, so evidence never went stale. It does now — and the answer came back in two
|
||
halves. Time-awareness re-evolved, on a 35-minute half-life nobody asked for.
|
||
<strong>It still lost every tier, drift included.</strong>
|
||
</p>
|
||
<div class="byline">
|
||
<span>source <b>exp-008-drift-evolution.md</b></span>
|
||
<span>corpus <b>corpus-drift, seed 3031</b></span>
|
||
<span>run <b>code_drift1 · 400/400 evals</b></span>
|
||
<span>status <b>complete · champions unchanged</b></span>
|
||
</div>
|
||
|
||
<ol class="toc">
|
||
<li><a href="#clock"><span class="n">01</span><span class="t">What the simulator gained</span></a></li>
|
||
<li><a href="#baseline"><span class="n">02</span><span class="t">The baseline, before any evolution</span></a></li>
|
||
<li><a href="#question"><span class="n">03</span><span class="t">Three outcomes, written before the run</span></a></li>
|
||
<li><a href="#verdict"><span class="n">04</span><span class="t">The verdict: a clock evolved, and it still lost</span></a></li>
|
||
<li><a href="#settled"><span class="n">05</span><span class="t">What it settles, and what it does not</span></a></li>
|
||
</ol>
|
||
</div>
|
||
|
||
<!-- ================= 01 · THE CLOCK ================= -->
|
||
<section id="clock">
|
||
<div class="shell">
|
||
<div class="sec-head">
|
||
<div class="sec-no">01</div>
|
||
<h2>What the simulator gained</h2>
|
||
<p class="sec-sub">
|
||
Two additions, both aimed at one honest weakness: a world where knowledge
|
||
never expires is a world that flatters routers which never forget.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="keyrow wide">
|
||
<div class="key">
|
||
<span class="kn">10<span class="u">min</span></span>
|
||
<div class="kl">
|
||
of simulated time between payments, one second per attempt — so lnd's
|
||
decay half-lives operate over spans that mean something
|
||
</div>
|
||
<div class="kf">candidates can read <span class="mono">view.Now()</span></div>
|
||
</div>
|
||
<div class="key">
|
||
<span class="kn">≥10</span>
|
||
<div class="kl">
|
||
background senders per gap, scaled to network size, each a naive
|
||
fee-optimising payer moving liquidity we never see
|
||
</div>
|
||
<div class="kf">amounts log-uniform, dust to half a channel</div>
|
||
</div>
|
||
<div class="key hi">
|
||
<span class="kn">0.42<span class="u">was 0.59</span></span>
|
||
<div class="kl">
|
||
what the champions now average across validation and test, down from
|
||
0.59 on the static hard corpus — drift costs everyone
|
||
</div>
|
||
<div class="kf">headroom the evolution run did not claim</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="prose">
|
||
<h3>The clock</h3>
|
||
<p>
|
||
The simulator previously had no notion of time at all. Attempts happened
|
||
in sequence and nothing aged, which quietly disabled half of lnd's design:
|
||
<span class="mono">PenaltyHalfLife</span> and the bimodal estimator's
|
||
seven-day liquidity relaxation are functions of elapsed time, and elapsed
|
||
time was always zero. lnd's mission control now runs on a virtual clock
|
||
that advances ten simulated minutes between payments and one second per
|
||
attempt, so its decay genuinely operates. Candidates get the same clock
|
||
through <span class="mono">view.Now()</span> — available, not suggested.
|
||
</p>
|
||
|
||
<h3>The traffic</h3>
|
||
<p>
|
||
Between our payments, a seeded population of background senders pays each
|
||
other: naive fee-optimising routers, at least ten per gap or one per ten
|
||
nodes, with amounts drawn log-uniformly from roughly dust up to half a
|
||
channel. Their transfers move hidden balances under per-channel
|
||
conservation, so liquidity sloshes without being created. Crucially the
|
||
process is seeded and replayed, so lnd, the seed router and every candidate
|
||
face the identical sequence of exogenous events — the drift is part of the
|
||
scenario, not a source of noise between contestants.
|
||
</p>
|
||
<p>
|
||
The effect on the difficulty is immediate. On the static hard corpus the
|
||
champions averaged about <span class="mono">0.59</span> across validation
|
||
and test; on the drift corpus they average about
|
||
<span class="mono">0.42</span>, with attempts per payment up from nine or
|
||
ten to around twelve. Nobody is comfortable here, which is the point: a
|
||
harder environment is the only thing that can pay for a better algorithm.
|
||
</p>
|
||
|
||
<div class="note">
|
||
<h4>the caveat this experiment exists to remove</h4>
|
||
<p>
|
||
Every result on the <a class="link" href="findings.html">findings</a>
|
||
page was produced in a world without drift, and the champions' complete
|
||
absence of time logic was partly an artifact of that world. Hard evidence
|
||
bounds cannot go stale if nothing changes them, so evolution was right
|
||
about the environment it was given — which is not the same as being right
|
||
about mainnet. This page is the test of exactly that, and
|
||
<a class="link" href="#verdict">§04</a> is the answer.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ================= 02 · BASELINE ================= -->
|
||
<section id="baseline">
|
||
<div class="shell">
|
||
<div class="sec-head">
|
||
<div class="sec-no">02</div>
|
||
<h2>The baseline, before any evolution</h2>
|
||
<p class="sec-sub">
|
||
Five routers, none of which has ever seen drift, scored on the new corpus.
|
||
Two findings fell out before the evolution run even started.
|
||
</p>
|
||
</div>
|
||
|
||
<figure>
|
||
<div class="fig-head">
|
||
<span class="fig-t">Composite objective on the drift corpus</span>
|
||
<span class="fig-n">Fig. 1 · higher is better</span>
|
||
</div>
|
||
<div class="plot resp" id="fig-drift"></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>
|
||
Note the axis: it tops out at <span class="mono">0.5</span>, where the
|
||
static-corpus figures ran to 0.8. Everything got harder. The ordering did
|
||
not change — the three evolved routers cluster at the top of both splits,
|
||
the hand-written seed sits in the middle, and lnd's production stack is
|
||
last <b>even though this is the first environment where its decay actually
|
||
runs</b>.
|
||
</figcaption>
|
||
</figure>
|
||
|
||
<div class="tw wide">
|
||
<table class="data">
|
||
<caption>exp-008 baseline · corpus-drift, 8 validation and 8 held-out test files</caption>
|
||
<thead>
|
||
<tr>
|
||
<th>router</th>
|
||
<th class="num">drift val</th>
|
||
<th class="num">drift test</th>
|
||
<th class="num">test success</th>
|
||
<th class="num">test attempts</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>lnd production stack<span class="sub">Dijkstra + mission control, decay now live</span></td>
|
||
<td class="num" data-l="drift val">0.213</td><td class="num" data-l="drift test">0.203</td>
|
||
<td class="num" data-l="test success">0.388</td><td class="num" data-l="test attempts">34.5</td>
|
||
</tr>
|
||
<tr>
|
||
<td>hand-written seed<span class="sub">~300 lines, cheapest path + blacklist</span></td>
|
||
<td class="num" data-l="drift val">0.320</td><td class="num" data-l="drift test">0.377</td>
|
||
<td class="num" data-l="test success">0.592</td><td class="num" data-l="test attempts">48.3</td>
|
||
</tr>
|
||
<tr>
|
||
<td>hb1<span class="sub">evolved, hard-regime specialist</span></td>
|
||
<td class="num" data-l="drift val">0.387</td><td class="num" data-l="drift test">0.455</td>
|
||
<td class="num" data-l="test success">0.642</td><td class="num" data-l="test attempts">11.8</td>
|
||
</tr>
|
||
<tr class="best">
|
||
<td>mx_c3<span class="sub">evolved, generalist</span></td>
|
||
<td class="num" data-l="drift val">0.380</td><td class="num" data-l="drift test">0.457</td>
|
||
<td class="num" data-l="test success">0.642</td><td class="num" data-l="test attempts">12.3</td>
|
||
</tr>
|
||
<tr>
|
||
<td>gen2<span class="sub">evolved, prose-seeded lineage</span></td>
|
||
<td class="num" data-l="drift val">0.383</td><td class="num" data-l="drift test">0.456</td>
|
||
<td class="num" data-l="test success">0.642</td><td class="num" data-l="test attempts">12.7</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="prose">
|
||
<h3 style="margin-top:2em">Finding one: hard bounds degrade gracefully</h3>
|
||
<p>
|
||
The prediction worth taking seriously was that interval beliefs would
|
||
<em>break</em> under drift. A <span class="mono">lowerOK</span> bound is an
|
||
assertion that an amount definitely passes; once strangers move the
|
||
balance, that assertion can simply be false, and a router that treats it as
|
||
proven has no mechanism for doubt.
|
||
</p>
|
||
<p>
|
||
It does not break. The three evolved routers hold roughly
|
||
<strong>2.2×</strong> lnd's objective on the held-out split at
|
||
<strong>a third of the attempts</strong> — 0.456 against 0.203, twelve
|
||
attempts against 34.5. The reason is asymmetry of cost: a stale bound that
|
||
is too optimistic costs one failed attempt, after which the evidence
|
||
updates and the interval narrows again. A stale bound is not a wrong model,
|
||
it is one retry.
|
||
</p>
|
||
|
||
<h3>Finding two: lnd's decay does not close the gap</h3>
|
||
<p>
|
||
This is the sharper result. The obvious defence of mission control's
|
||
time-decayed penalties was that our simulator never let them work. Now they
|
||
work, over ten-minute gaps against liquidity that genuinely moved, and the
|
||
production stack is still last — 0.203 on the held-out split, at 34.5
|
||
attempts per payment for a 0.388 success rate.
|
||
</p>
|
||
<p>
|
||
So decay <em>as lnd implements it</em> is not the missing ingredient.
|
||
Whatever drift-awareness helps in this environment has to look different
|
||
from a scalar pair-penalty healing on a one-hour half-life. Note also what
|
||
the champions' 0.642 success at twelve attempts says about the ceiling:
|
||
drift costs everyone success, and there is a lot of unclaimed room between
|
||
0.456 and a router that handles staleness deliberately. That room is still
|
||
unclaimed: the router bred here to handle staleness deliberately reached
|
||
0.417 (<a class="link" href="#verdict">§04</a>).
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ================= 03 · THE QUESTION ================= -->
|
||
<section id="question">
|
||
<div class="shell">
|
||
<div class="sec-head">
|
||
<div class="sec-no">03</div>
|
||
<h2>Three outcomes, written before the run</h2>
|
||
<p class="sec-sub">
|
||
<span class="mono">code_drift1</span>: pure GEPA, codex/gpt-5.6-sol
|
||
reflection, small seed plus the insights prompt, 400 evaluations on
|
||
corpus-drift. This ledger was published while it was still running; the
|
||
flags are how each row resolved.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="prose">
|
||
<p>
|
||
The setup deliberately did not prescribe the answer. The reflection prompt
|
||
described drift neutrally — payments happen, time passes, other senders
|
||
exist — and flagged the hard-bounds insight as something learned in a static
|
||
world, a caveat rather than an instruction. Nothing told the model to add
|
||
decay, and nothing told it not to. The success criterion was beating the
|
||
champions on the held-out drift test; the interesting part came after, when
|
||
the winner was read for any function of
|
||
<span class="mono">view.Now()</span> or of evidence age.
|
||
</p>
|
||
|
||
<p>
|
||
Three outcomes, all of them worth having. The run delivered the mechanism
|
||
of the second and the verdict of the third:
|
||
</p>
|
||
</div>
|
||
|
||
<div class="ledger">
|
||
<div class="ledger-row">
|
||
<div class="verb"><b>Decay</b>re-emerges</div>
|
||
<div class="ledger-cell now">
|
||
<h4>what we would see</h4>
|
||
<p>
|
||
Evolved candidates that discount old evidence on a clock, in some form
|
||
— a half-life on confidence, an expiry on bounds, a penalty that heals.
|
||
</p>
|
||
</div>
|
||
<div class="ledger-cell next">
|
||
<h4>what it would mean</h4>
|
||
<p>
|
||
A vindication of lnd's rationale from an independent search, with
|
||
<strong>evolved constants</strong> instead of hand-picked ones. The
|
||
interesting artifact would be the half-life it chooses, and how it
|
||
compares to the shipped one hour.
|
||
</p>
|
||
</div>
|
||
<div class="resolved">this happened<i> · confidence halves every 35
|
||
virtual minutes, hard bounds expire outright at 20 — evolved
|
||
constants against lnd's shipped hour</i></div>
|
||
</div>
|
||
|
||
<div class="ledger-row">
|
||
<div class="verb"><b>Something better</b>emerges</div>
|
||
<div class="ledger-cell now">
|
||
<h4>what we would see</h4>
|
||
<p>
|
||
Not decay but a different treatment of staleness: intervals that widen
|
||
with elapsed time, confidence that erodes while the bound itself is
|
||
kept, re-probing scheduled by age rather than by failure.
|
||
</p>
|
||
</div>
|
||
<div class="ledger-cell next">
|
||
<h4>what it would mean</h4>
|
||
<p>
|
||
The best case, and a <strong>concrete design proposal for lnd</strong>:
|
||
keep the evidence, age the certainty. That is a change mission control
|
||
could adopt without giving up its own structure.
|
||
</p>
|
||
</div>
|
||
<div class="resolved">the form, not the payoff<i> · what evolved is
|
||
exactly this — keep the judgment, fade the trust in it, slide back
|
||
toward the prior — and it still lost every tier</i></div>
|
||
</div>
|
||
|
||
<div class="ledger-row">
|
||
<div class="verb"><b>Intervals</b>still win untouched</div>
|
||
<div class="ledger-cell now">
|
||
<h4>what we would see</h4>
|
||
<p>
|
||
The winner improves on the champions without referencing time at all —
|
||
better attribution, better retries, better splitting, and still no
|
||
clock.
|
||
</p>
|
||
</div>
|
||
<div class="ledger-cell next">
|
||
<h4>what it would mean</h4>
|
||
<p>
|
||
That time-decay is <strong>overweighted</strong> in current designs:
|
||
evidence-count confidence would be carrying the load even when the
|
||
evidence really can go stale. Also the least comfortable result to
|
||
publish, which is a reason to state the criterion in advance.
|
||
</p>
|
||
</div>
|
||
<div class="resolved">the verdict, by another route<i> · the winner did
|
||
reference time, and did not improve on the champions — a time-less
|
||
router (gen2, 0.456) still leads the drift tier</i></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="prose">
|
||
<p style="margin-top:2em">
|
||
The result did not land on one row, and rounding it to one would be the
|
||
convenient version. <strong>Mechanically it is the first row, in the shape
|
||
the second asked for, with the third row's verdict.</strong> Selection under
|
||
genuine staleness pressure did invent decay — of confidence in evidence
|
||
rather than of penalties — and the router carrying it still finished behind
|
||
three time-less ancestors on the corpus it was bred for.
|
||
</p>
|
||
|
||
<div class="sidenote">
|
||
<h4>what this run cannot settle</h4>
|
||
<p>
|
||
One drift model, and a naive one: background senders optimise fees and
|
||
nothing else, there is no fee-market feedback, no channel opens or
|
||
closes, and no correlation between their traffic and ours. The corpus is
|
||
eight validation and eight test files from a single seed. A router that
|
||
wins here has beaten <em>this</em> drift process, and the next honest
|
||
objection is that real mainnet flow is bursty and correlated in ways this
|
||
model does not capture.
|
||
</p>
|
||
<p>
|
||
The verdict section of
|
||
<span class="mono">exp-008-drift-evolution.md</span> is now written, and
|
||
it is what follows. The run's own telemetry — score curve, lineage,
|
||
per-candidate diffs — is on the
|
||
<a class="link" href="index.html#run">overview page</a>.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ================= 04 · THE VERDICT ================= -->
|
||
<section id="verdict">
|
||
<div class="shell">
|
||
<div class="sec-head">
|
||
<div class="sec-no">04</div>
|
||
<h2>The verdict: a clock evolved, and it still lost</h2>
|
||
<p class="sec-sub">
|
||
<span class="mono">code_drift1</span> spent all 400 evaluations, accepted 51
|
||
candidates and exited clean. Its winner, <span class="mono">drift1</span>, is
|
||
the first evolved router in this project that reads the time — and fourth of
|
||
six on the corpus it was bred for.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="keyrow wide">
|
||
<div class="key">
|
||
<span class="kn">35<span class="u">min</span></span>
|
||
<div class="kl">
|
||
half-life on confidence in a belief:
|
||
<span class="mono">conf·exp(−ln2·age/35min)</span>, an evolved constant
|
||
against lnd's shipped hour
|
||
</div>
|
||
<div class="kf">payments are ten virtual minutes apart</div>
|
||
</div>
|
||
<div class="key">
|
||
<span class="kn">20<span class="u">min</span></span>
|
||
<div class="kl">
|
||
after which <span class="mono">lowerOK</span> and
|
||
<span class="mono">upperFail</span> are zeroed outright — proven bounds
|
||
demoted to hints
|
||
</div>
|
||
<div class="kf">an expiry, not a fade</div>
|
||
</div>
|
||
<div class="key hi">
|
||
<span class="kn">0.417<span class="u">vs 0.456</span></span>
|
||
<div class="kl">
|
||
drift1 on the held-out drift test against gen2, which never saw drift,
|
||
on the same seed and the same 400-eval budget
|
||
</div>
|
||
<div class="kf">the drift-bred router lost on drift</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="prose">
|
||
<h3>What the clock does</h3>
|
||
<p>
|
||
drift1 keeps its lineage's belief state — per-directed-channel
|
||
<span class="mono">lowerOK</span> and <span class="mono">upperFail</span>
|
||
bounds with a point estimate between them — and adds one field:
|
||
<span class="mono">updatedAt</span>. Everything time-aware follows from that
|
||
stamp. Confidence in a belief decays exponentially on a 35-minute half-life,
|
||
so a fresh observation still carries 82% of its weight at the next payment
|
||
and about two-thirds by the third. Below a floor of
|
||
<span class="mono">0.01</span> the belief is not weak, it is gone.
|
||
</p>
|
||
<p>
|
||
Twenty minutes in, the two hard bounds are zeroed outright. The comment
|
||
above that branch is the design in one line: <em>bounds become hints rather
|
||
than permanent facts after substantial age</em>. And the probability model
|
||
reads
|
||
<span class="mono">conf·learned + (1−conf)·prior</span> — fresh evidence
|
||
dominates, aging evidence slides back toward the rediscovered bimodal prior,
|
||
dead evidence leaves the prior alone.
|
||
</p>
|
||
|
||
<h3>Why this is not lnd's decay</h3>
|
||
<p>
|
||
lnd fades a <em>judgment</em>: a failure earns a pair-penalty of full weight,
|
||
and <span class="mono">getWeight</span> relaxes it on a one-hour half-life
|
||
back toward an apriori scalar, while successes never decay at all. drift1
|
||
keeps the judgment and fades its <em>trust</em> in the observation behind it,
|
||
symmetrically for passes and failures, recovering toward a prior it learned
|
||
itself. That is a posterior collapsing toward a prior, not a penalty on a
|
||
timer. Nothing in the prompt suggested either form.
|
||
</p>
|
||
</div>
|
||
|
||
<figure>
|
||
<div class="fig-head">
|
||
<span class="fig-t">How fast an old observation stops counting</span>
|
||
<span class="fig-n">Fig. 2 · virtual minutes</span>
|
||
</div>
|
||
<div class="plot" id="fig-decay"></div>
|
||
<div class="scrollhint">scroll the chart sideways →</div>
|
||
<div class="legend">
|
||
<span class="item"><i class="line" style="background:#a83f22"></i>
|
||
drift1 — confidence in the evidence, 35-min half-life</span>
|
||
<span class="item"><i class="line" style="background:#2f6ea8;height:0;border-top:1.5px dashed #2f6ea8"></i>
|
||
lnd — weight on a failure penalty, 1-hour half-life</span>
|
||
</div>
|
||
<figcaption>
|
||
The two curves are <b>not the same quantity</b>, which is the point: lnd's
|
||
line is how much a failure still hurts, drift1's is how much an observation
|
||
is still believed. Drawn on one axis because both answer “how long does an
|
||
old look at this channel keep governing the route”. drift1 forgets faster
|
||
than lnd, expires its hard bounds at twenty minutes on top of that, and
|
||
discards the belief entirely once confidence falls under
|
||
<span class="mono">0.01</span> — roughly four hours idle, or twenty payments
|
||
at this corpus's ten-minute gap.
|
||
</figcaption>
|
||
</figure>
|
||
|
||
<figure>
|
||
<div class="fig-head">
|
||
<span class="fig-t">Held-out drift test, after evolution</span>
|
||
<span class="fig-n">Fig. 3 · higher is better</span>
|
||
</div>
|
||
<div class="plot resp" id="fig-drift-final"></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>
|
||
The same axis as Fig. 1, so the bars are directly comparable. drift1 is the
|
||
only router here that was evolved <b>on</b> drift, and it lands between the
|
||
hand-written seed and the three static-bred evolved routers. Nothing moved
|
||
at the top: mx_c3 still leads the tier at 0.457, and the ordering of Fig. 1
|
||
survives the run that was meant to overturn it.
|
||
</figcaption>
|
||
</figure>
|
||
|
||
<div class="tw wide">
|
||
<table class="data">
|
||
<caption>exp-008 verdict · composite objective, four held-out tiers, all sealed from the run</caption>
|
||
<thead>
|
||
<tr>
|
||
<th>router</th>
|
||
<th class="num">drift test</th>
|
||
<th class="num">hard test</th>
|
||
<th class="num">OOD v2</th>
|
||
<th class="num">mainnet</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>lnd production stack<span class="sub">Dijkstra + mission control</span></td>
|
||
<td class="num" data-l="drift test">0.203</td><td class="num" data-l="hard test">0.309</td>
|
||
<td class="num" data-l="OOD v2">0.357</td><td class="num" data-l="mainnet">0.694</td>
|
||
</tr>
|
||
<tr>
|
||
<td>hand-written seed<span class="sub">~300 lines, cheapest path + blacklist</span></td>
|
||
<td class="num" data-l="drift test">0.377</td><td class="num" data-l="hard test">0.530</td>
|
||
<td class="num" data-l="OOD v2">0.487</td><td class="num" data-l="mainnet">0.762</td>
|
||
</tr>
|
||
<tr>
|
||
<td>hb1<span class="sub">evolved, hard-regime specialist</span></td>
|
||
<td class="num" data-l="drift test">0.455</td><td class="num" data-l="hard test">0.586</td>
|
||
<td class="num" data-l="OOD v2">0.545</td><td class="num" data-l="mainnet">0.790</td>
|
||
</tr>
|
||
<tr class="best">
|
||
<td>mx_c3<span class="sub">evolved, generalist — champion of record</span></td>
|
||
<td class="num" data-l="drift test">0.457</td><td class="num" data-l="hard test">0.583</td>
|
||
<td class="num" data-l="OOD v2">0.581</td><td class="num" data-l="mainnet">0.791</td>
|
||
</tr>
|
||
<tr>
|
||
<td>gen2<span class="sub">evolved, prose-seeded, no clock</span></td>
|
||
<td class="num" data-l="drift test">0.456</td><td class="num" data-l="hard test">0.565</td>
|
||
<td class="num" data-l="OOD v2">0.563</td><td class="num" data-l="mainnet">0.787</td>
|
||
</tr>
|
||
<tr>
|
||
<td>drift1<span class="sub">evolved on drift, 1,147 lines, has a clock</span></td>
|
||
<td class="num" data-l="drift test">0.417</td><td class="num" data-l="hard test">0.580</td>
|
||
<td class="num" data-l="OOD v2">0.544</td><td class="num" data-l="mainnet">0.790</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="prose">
|
||
<h3 style="margin-top:2em">The decisive cut: drift1 against gen2</h3>
|
||
<p>
|
||
Comparing drift1 to the champions is a little unfair — they had 900
|
||
evaluations across two runs, it had 400. The comparison that is fair is
|
||
<span class="mono">gen2</span>. Same small seed, same insights-in-the-prompt
|
||
design, same 400-evaluation budget, and gen2 <em>never saw drift</em>,
|
||
because the virtual clock did not exist when it was bred. The static-bred,
|
||
time-less router scores <strong>0.456</strong> on the drift corpus. The
|
||
drift-bred, time-aware one scores <strong>0.417</strong>. Whatever the clock
|
||
bought, it did not cover what the mutations spent building it.
|
||
</p>
|
||
<p>
|
||
The static tiers say the same thing from the other direction. drift1 holds
|
||
0.580 on the sealed hard test and 0.790 on the mainnet snapshot at 2.4
|
||
attempts per payment — champion-class, 8× better than lnd's 19.8. So the
|
||
time machinery cost it nothing where nothing drifts, and it bought nothing
|
||
where things do. On drift itself it settles 60% of payments at 12.2 attempts,
|
||
against mx_c3's 64% at 12.3.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ================= 05 · WHAT IT SETTLES ================= -->
|
||
<section id="settled">
|
||
<div class="shell">
|
||
<div class="sec-head">
|
||
<div class="sec-no">05</div>
|
||
<h2>What it settles, and what it does not</h2>
|
||
<p class="sec-sub">
|
||
The open question from exp-006 onward was whether the champions'
|
||
timelessness was a design property or a simulator artifact. At this level of
|
||
churn, it is a design property.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="prose">
|
||
<h3>lnd's rationale is validated. Its necessity is not.</h3>
|
||
<p>
|
||
Stale knowledge should lose force — an independent search that was never told
|
||
about decay invented something to that effect the moment its evidence could
|
||
actually go stale, and that mechanism won selection inside its own lineage
|
||
rather than being carried along neutrally. The intuition behind
|
||
<span class="mono">PenaltyHalfLife</span> is real, and it is now confirmed
|
||
from the outside.
|
||
</p>
|
||
<p>
|
||
What is not confirmed is that a router needs it. Both decaying designs on
|
||
this page lose to routers that simply keep their evidence: lnd finishes last
|
||
at 0.203 with its half-lives finally operating, and drift1 finishes behind
|
||
three time-less ancestors. Decay buys insurance against a cost the interval
|
||
design barely pays.
|
||
</p>
|
||
|
||
<div class="note">
|
||
<h4>the asymmetry that decides it</h4>
|
||
<p>
|
||
When drift1 zeroes a bound at twenty minutes it throws away information
|
||
that is usually still approximately right, and it pays for that on every
|
||
route it prices afterwards. hb1 and mx_c3 keep the bound, are occasionally
|
||
wrong, and pay <strong>one extra attempt</strong> when they are — an
|
||
attempt that also refreshes the belief. The objective charges 0.01 per
|
||
extra attempt. That is a small bill next to planning against a prior when
|
||
you had a measurement.
|
||
</p>
|
||
</div>
|
||
|
||
<h3>Champions of record: unchanged, now on four tiers</h3>
|
||
<p>
|
||
<strong>hb1 and mx_c3</strong> stay the champions, with mx_c3 leading or
|
||
tying every tier except the hard test. drift1 is kept as source and written
|
||
up, not promoted — the same disposition as the
|
||
<a class="link" href="findings.html#ceiling">gen2</a> winner. It is the only
|
||
artifact in this project where an evolutionary search invented decay on its
|
||
own, and you can see exactly which form it chose.
|
||
</p>
|
||
|
||
<div class="sidenote">
|
||
<h4>the caveats that survive the verdict</h4>
|
||
<p>
|
||
<b>One drift intensity.</b> Ten-minute gaps and roughly one background
|
||
payment per ten nodes per gap. <b>One traffic model:</b> naive
|
||
fee-optimising senders, no fee market, no bursts, no correlation with our
|
||
own flow. <b>One budget:</b> 400 evaluations against a champion lineage
|
||
that accumulated its Pareto route search, bidirectional evidence and shard
|
||
ladders over 900. drift1's deficit is plausibly a budget deficit as much as
|
||
a mechanism deficit.
|
||
</p>
|
||
<p>
|
||
So the honest claim is narrow: time logic did not pay for itself in this
|
||
environment at this budget, not that it can never pay. A heavier churn
|
||
rate, bursty or adversarial traffic, or a longer run could all tip it back.
|
||
</p>
|
||
</div>
|
||
|
||
<div class="note">
|
||
<h4>next: exp-010, splitting pressure</h4>
|
||
<p>
|
||
The environment lever worked once — drift is genuinely harder, and everyone
|
||
lost ground on it — but it did not change the ranking, so the next
|
||
experiment pushes on the other unexercised axis. The champions price their
|
||
shards one route at a time; joint route-set planning, Pickhardt-style
|
||
min-cost flow across shards, has never been under selection pressure
|
||
because the corpus rarely forces a split. exp-010 makes it force one, on a
|
||
corpus of unequal parallel corridors.
|
||
</p>
|
||
<p>
|
||
It has since closed, and it rhymes with this page: three separate proposer
|
||
lineages all evolved joint route-set planning, the deepest of them tied a
|
||
champion on the corpus it was bred for, and none of them beat mx_c3 across
|
||
the held-out tiers. The environment elicited the mechanism again; the
|
||
champions still stand
|
||
(<a class="link" href="findings.html#splitting">the splitting verdict</a>).
|
||
</p>
|
||
<p>
|
||
Its follow-up, exp-010b, went after the “one drift intensity” caveat above
|
||
from the other side: traffic now moves on every <em>attempt</em> boundary
|
||
rather than only between payments, and shards hold liquidity until the
|
||
whole payment settles, so a long reactive ladder pays for the churn it
|
||
sits through. That reordered the baseline — lnd fell to last at 105
|
||
attempts per payment — and the drift-bred mechanism it elicited is the one
|
||
this page would predict: an evolved router that <em>relaxes</em> its hard
|
||
bounds after repeated failure so a moving network can be re-probed. It
|
||
burned 57 attempts per payment doing it, which is the same asymmetry as
|
||
above with the sign flipped
|
||
(<a class="link" href="findings.html#atomic">the atomic verdict</a>).
|
||
</p>
|
||
</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 settled results behind this experiment — mainnet validation, the
|
||
paradigm-over-parameters pivot, an anatomy of the evolved algorithms against
|
||
lnd's, and the paradigm ceiling that made changing the environment the only
|
||
move left.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
</main>
|
||
|
||
<div class="shell">
|
||
<footer class="site-footer">
|
||
<span>lnd × GEPA — Lightning routing evolution</span>
|
||
<span><a href="index.html">overview</a> · <a href="findings.html">findings</a> · <a href="index.html#run">live run</a></span>
|
||
</footer>
|
||
</div>
|
||
|
||
<script src="app.js"></script>
|
||
</body>
|
||
</html>
|