mirror of
https://github.com/lightningnetwork/lnd.git
synced 2026-08-14 12:42:48 +02:00
In this commit, we add §12 — the degraded-attribution ladder, its two tables, the five findings, and the anomaly labelled as an anomaly — plus the two exp-019 timeline entries, and we sweep the 8.6x claim across the whole site: every place that quoted the attempt ratio as a live headline now carries the retirement (the ratio was a perfect-channel figure; under realistic degradation the edge converts to success), while historical narration keeps its numbers and gains a pointer instead of a rewrite. The masthead moves to nineteen experiments, title-defended champions, and attribution-tested status.
728 lines
35 KiB
HTML
728 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, sharp-bimodal 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 — title defended</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, sharp-bimodal 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 — title defended (exp-020)</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 on the
|
||
perfect failure channel these tiers use
|
||
(<a class="link" href="findings.html#attribution">exp-019</a> retired the
|
||
ratio). 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>
|