Skip to content

routing: add an experimental interval router behind a config flag - #11048

Draft
Roasbeef wants to merge 9 commits into
lightningnetwork:masterfrom
Roasbeef:interval-router-rebased
Draft

routing: add an experimental interval router behind a config flag#11048
Roasbeef wants to merge 9 commits into
lightningnetwork:masterfrom
Roasbeef:interval-router-rebased

Conversation

@Roasbeef

@Roasbeef Roasbeef commented Aug 8, 2026

Copy link
Copy Markdown
Member

In this PR, we add a second routing engine to lnd, selectable with
routerrpc.router=interval and off by default. It replaces the way lnd
learns from payment results, and it leaves everything else (the payment
lifecycle, HTLC dispatch, mission control's history and RPCs) exactly as
it is today.

How it improves on the current algorithm

Today, lnd learns from a failed payment by penalizing a node pair. Mission
control records the failure, a half-life timer fades the penalty, and path
finding avoids the pair until enough time has passed. The amount is chosen
before the search begins: path finding answers "can the graph carry X," and
when the answer is no, the payment loop halves X and searches again.

The interval router keeps a different memory. For each channel, in each
direction, it tracks a liquidity interval: the largest amount it has
watched succeed, the smallest amount it has watched fail, and an estimate
in between. Three practical differences follow from that one change.

First, a failure records an amount, not a verdict. A channel that just
refused 400,000 sats is still the obvious way to send 40,000, so the
router keeps using it below the bound instead of routing around it for
every amount. There is no clock anywhere in the model, because a bound
does not need to be forgiven; it needs to be contradicted by a newer
observation.

Second, every observation teaches both directions. Liquidity that is
missing on one side of a funding output sits on the other side, so a
failure toward a peer is also evidence about the path back. Mission
control never draws that inference, and it is free information: in our
measurements it accounts for roughly half of the reduction in payment
attempts.

Third, splitting is planned rather than reactive. For each route request
the session builds a ladder of candidate shard sizes, including sizes
derived from amounts this payment has already proven do not fit, finds a
route for each rung, and takes the best pairing. The halving loop
discovers a workable size by failing toward it; the interval router
computes one from the bounds it already holds.

The gains show up where knowledge matters. On a simulated snapshot of the
real graph (12,161 nodes, real channel policies), the interval router
completes payments with 2.5 attempts on average where stock lnd needs
19.8, at a higher success rate. Under realistic error attribution, where
a fraction of failures are unreadable, stock lnd's give-up rate more than
doubles while the interval router's success holds flat: penalizing a
whole route in both directions for an error nobody can read turns out to
be the single most expensive habit in the current design. And because the
search prices fees against the payment's actual remaining budget, the fee
limit can bind during path finding rather than being discovered when a
route is rejected.

How it was developed

The design was not sketched on a whiteboard; it was found by search, then
rebuilt by hand.

We first built a payment simulator into this codebase: hidden per-channel
balances, real forwarding checks, seeded graphs, and a router interface
that owns both route selection and splitting. We then ran an evolutionary
search (LLM-driven program synthesis, scored only by simulated payment
outcomes) over whole routing algorithms, with lnd's production stack as
the baseline. Across dozens of independent runs and more than thirty
controlled experiments, every winning candidate converged on the same
paradigm: drop the per-pair penalties, drop time decay, and keep
per-direction liquidity intervals instead.

The code in this branch is not machine-written. We distilled the paradigm
into a hand-written implementation inside lnd's real payment lifecycle,
then spent six adversarial benchmark rounds trying to break it. Those
rounds caught real bugs (a fee term whose units meant no budget could
ever bind, a classifier that read a budget's remainder as its existence,
and a subtle case where misattributed failures manufactured false
evidence of a channel's health), and each fix was validated against the
same battery before it stayed. The final configuration beats stock lnd on
all fourteen simulated benchmark tiers with zero losses, holds its
margins under lnd's default fee limits, and reproduces its lead on an
externally generated graph whose balance distribution none of our tools
ever fit.

Every number above comes from a simulator, and the limitations section
below says so plainly. The simulator, corpora, and experiment writeups
live in a research fork and are deliberately not part of this PR; this
branch carries only the router, its tests, and its documentation.

What is in the branch

In dependency order, which is also the order to review:

  1. A seam letting a payment session hear the outcomes of the attempts it handed
    out. The lifecycle reported to mission control and nowhere else; a session
    with beliefs of its own needs the same stream. Optional, so the stock session
    does not implement it and nothing changes with the flag off.
  2. The belief store: the interval, its update rules, and a bimodal prior whose
    scale is a fraction of capacity rather than a fixed number of millisatoshis,
    which is what lets one set of constants work across channel sizes.
  3. A label setting search that keeps a bounded set of Pareto-incomparable labels
    per node, because a route that is cheaper but carries a larger amount is not
    comparable to one that is dearer and carries less.
  4. The session: the shard ladder, the per-payment state, and the fallback for
    payment shapes the router does not serve.
  5. Config wiring, sample conf, and the release note.
  6. Persistence to the native SQL store, with a new liquidity_intervals table.
  7. Pricing a shard against HTLCs we already hold on interior channels.
  8. A budget derived exchange rate between fees and reliability.
  9. A quarantine for failures that cannot say where they happened, and the trust
    boundary that decides what may release one. This is the part with the most
    argument behind it and the least measured gain; the two sections below say
    why it is here anyway.

Evidence

The design was arrived at by evolutionary search against an in-process payment
simulator, and then validated against lnd's production stack on held-out
scenarios. What the branch rests on:

  • In simulation, the router beats stock lnd on all 14 benchmark tiers,
    across clean, degraded, split, atomic and mainnet-derived scenario
    families, with the paired confidence interval excluding zero on every
    one. The score behind these comparisons is a payment objective: success
    rate, minus small penalties for extra attempts and for fees paid.
  • The margins reproduce on files nobody had seen. Regenerating the
    corpora fresh, thirty files per family, the leads over stock lnd come
    back larger than the original tiers had shown: the hard family lands between +0.16 and +0.26 of
    objective, every one at p below 2e-3, and mainnet at +0.096. The collapse that
    degraded attribution induces in stock lnd reproduces on the unseen files too,
    which is the part that was most worth checking, since it is the finding the
    whole design leans on.
  • Production-default fee limits. The margins hold when payments carry the
    fee limit lnrpc.CalculateFeeLimit gives them by default, which is the limit
    every RPC payment actually carries.
  • External-graph parity. On a channel graph generated outside this work, the
    router holds parity with the best routers the search produced, which is the
    closest thing available to an out-of-sample check on a topology nobody here
    chose.
  • An integration test over a three hop network with the flag on, covering a
    payment that settles, one that fails on liquidity at the middle hop, and a
    smaller one that settles immediately afterwards with nothing reset, which is
    the behaviour the whole design is for.

What this is not

Stated plainly, because the evidence above is easy to over-read.

  • Everything above was measured in simulation. No number here comes from
    mainnet. The simulator's liquidity is drawn from a generator, and while the
    mainnet-derived tiers use real topology and real policies, their balances are
    synthetic. That is the single largest caveat on the whole branch.

  • The scenarios are ones we chose. Thirteen paired tiers moving the
    liquidity family, the amount family and the graph itself did not change the
    ordering, which is evidence against overfitting rather than proof of its
    absence.

  • One interaction was found and explained, and the fix rests on the mechanism
    rather than on a measured gain.
    A tier mixing unreadable errors with shifted
    blame behaved worse than either ingredient alone. The cause is the
    quarantine's trust boundary: a failure that names the wrong hop makes the
    router write a lower bound on the channel that actually refused, and the
    quarantine was reading that bound as proof of innocence, letting the culprit
    out of every suspicion and concentrating the blame on its neighbours. Two
    things establish that. Ablating the ingredients separates them cleanly, since
    neither unreadable errors nor shifted blame does this alone. And ground truth
    counters name the victims: on the mixed tier 9.6% of promoted bounds landed on
    channels that had never failed, against 0.0% when only unreadable errors were
    present.

    What does not survive is the size of it. On thirty freshly generated files of
    that family the objective-level effect is indistinguishable from zero, in both
    directions, and the ten files it was first seen on could not have pinned an
    effect that small against a per-file spread reaching 0.29. So we keep the fix
    on the grounds that it stops the router accepting evidence that misattribution
    manufactures, and we do not claim it buys anything measurable. Its cost is
    likewise not measurable at thirty files, which is the other half of why it
    stays.

  • The quarantine is severable. It sits behind DisableQuarantine and
    can be switched off, or dropped by reverting its commits, without
    touching anything else.

  • The beliefs are simulator-shaped in one specific way. Several constants in
    the probability model were selected by a search against a generator whose
    liquidity distribution the constants then came to fit. The mechanism is what
    transfers; the constants are the part to be suspicious of.

Known limitations

  • One deficit against the evolved routers survives the wider corpus. On
    degraded mainnet the router sits 0.021 of objective below the best of them,
    with the interval spanning -0.042 to +0.001 at thirty files: the direction has
    held everywhere it has been measured, and it has never been separated from
    zero. What the other router has there, and this one does not, is that
    degrading attribution costs it no success at all, 0.557 either way. We have
    not reproduced that invariance and we do not claim it.
  • Payments to blinded paths are served by the stock session. Inside a blinded
    path there is no channel to key a belief on, and an error from inside one
    names nothing further in. The fallback is transparent: the session handed out
    is the one the stock source would have produced.
  • A resumed payment's in-flight HTLCs are not counted as holds, because the
    router did not choose their routes and cannot say which channels they sit on.
  • An ambiguous failure is recorded against the node pair rather than the
    channel, since non-strict forwarding means the evidence cannot name one.
  • Searching costs more than a single Dijkstra run, which is the main reason the
    router is off by default.
  • Persistence needs the native SQL backend. Elsewhere the router starts cold.

Reviewing this

The flag is off by default, and with it off none of the new code is constructed:
the server builds the same session source it always did, and the lifecycle seam
is a type assertion the stock session does not satisfy. The commits build and
pass tests individually.

docs/interval_routing.md explains the algorithm for someone who has not seen
this line of work, and is the place to start.

Roasbeef added a commit to Roasbeef/lnd that referenced this pull request Aug 8, 2026
In this commit, we point both release note entries at the request
that carries this work, lightningnetwork#11048.
Roasbeef added a commit to Roasbeef/lnd that referenced this pull request Aug 8, 2026
In this commit, we point both release note entries at the request
that carries this work, lightningnetwork#11048.
In this commit, we let a payment session hear what became of the routes
it handed out. Today the payment lifecycle reports every attempt to
mission control and to nothing else, which is enough while the only view
of network liquidity in the system is the node wide one mission control
owns. A session that carries a view of its own has no way to see the
results of its own work, so we give it one.

The new PaymentResultReporter interface is optional. The lifecycle type
asserts on it after it has finished talking to mission control, and a
session that does not implement it never hears a thing, which is exactly
what the session lnd ships expects. Nothing about the existing flow
moves: mission control still decides whether a failure is terminal, and
the reporting happens after that decision rather than instead of it.

The third method is the one worth explaining. A session that tracks the
attempts it produced needs to know when no further outcome is coming,
because a route it returned may never have reached the switch at all, in
which case nothing else would ever tell it so. The lifecycle calls it on
the way out, from a defer beside the one that stops the shard goroutines.

We also lift the two additional edge helpers off the session and onto the
edge map itself, so that a second session implementation can embed the
map and pick up both interface methods without copying them.
In this commit, we add the thing the router reasons over. Mission control
remembers a penalty per node pair and lets it fade on a half life. This
remembers an amount range per directed channel: the largest amount it has
watched pass, the smallest it has watched fail, and an estimate in
between, with a confidence and a classification saying which side of the
bimodal liquidity distribution the channel appears to sit on.

Three kinds of observation write to it. A probe is what we learn when a
failure comes back from a node further along the route than a given hop,
which proves that hop forwarded. A failure drops the upper bound. A
settlement is different in kind from both: the balance really has moved,
so the forward interval slides down by the settled amount and the reverse
interval slides up by the same. Every observation writes both directions,
because liquidity sitting on one side of a funding output is not sitting
on the other, and nothing in mission control makes that inference.

The probability model on top is a branch table ordered by how much the
evidence proves, from a bound we watched hold down to a bimodal prior we
have nothing behind. The prior expresses its scale as a fraction of
capacity rather than as an absolute number of millisatoshis, which is
what lets it mean the same thing on channels that differ in size by
orders of magnitude. There is no clock anywhere in the file.

Two properties are worth calling out because they are load bearing rather
than incidental. A belief seeded in from durable storage is marked as
restored, and the model then refuses to let either of its bounds speak
with certainty: this model has no clock, so an amount it calls impossible
is never attempted, and the attempt is the only thing that could correct
a bound that has gone stale. And the store carries an overlay of the
amounts we currently have committed in flight, kept apart from the
beliefs and never persisted, because it records what we are doing to the
network rather than what we believe about it.
In this commit, we add the search that turns the beliefs into a route. It
walks backwards from the target the same way lnd's own path finder does,
and it reuses the machinery that makes that walk correct: the edge
unifier that picks a policy per node pair, the bandwidth hints that speak
for our own channels, the fee and time lock limits, the onion payload
accounting, and the feature validation of every node it would route
through.

Two things differ. The cost of a hop is the negative log of its
probability plus terms for fee, depth and how much of a channel the
payment would fill, rather than a fee divided through by a probability.
Additivity is what makes the search tractable, and it is far gentler on a
route the model is merely unsure about. The other difference is that a
node keeps a bounded set of Pareto-incomparable labels rather than a
single best distance. Because the search runs backwards and fees accrue
as it goes, a route that is cheaper but carries a larger amount is
genuinely incomparable to one that is dearer and carries less, since the
larger amount may be refused further upstream.

The units of the fee term decide whether a fee budget can reach the
search at all, which is worth stating plainly because it is easy to get
wrong. Converting a fee at a rate proportional to the amount reads as a
willingness to pay a fifth of the payment for one factor of e in
reliability, and no budget anybody sets is within reach of that, so the
term never binds. A payment carrying a budget therefore prices fees
against the budget itself, half of what remains, bounded at both ends and
absolute rather than relative, so the ceiling tightens as the payment
grows. A payment with no budget has nothing to derive a rate from and
falls back to the amount relative form.

Two smaller rules follow from the same concern. A node keeps the cheapest
label it holds whatever that label scores, but only when the payment has
a budget that could bind, since a slot spent on price is a slot wasted
for a payment choosing on reliability alone. And the search is bounded on
hops, labels per node and total expansions, because it is more expensive
than a single distance Dijkstra by construction.
@github-actions github-actions Bot added the severity-critical Requires expert review - security/consensus critical label Aug 8, 2026
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown

🔴 PR Severity: CRITICAL

gh pr view | 34 files | 8922 lines changed

🔴 Critical (8 files)
  • server.go - core server coordination, wires up the new interval router
  • sqldb/migrations.go - registers a new database migration
  • sqldb/sqlc/migrations/000016_liquidity_intervals.up.sql - schema migration
  • sqldb/sqlc/migrations/000016_liquidity_intervals.down.sql - schema migration
  • sqldb/sqlc/queries/liquidity_intervals.sql - new SQL queries backing the migration
  • sqldb/sqlc/liquidity_intervals.sql.go - generated store code for the new tables
  • sqldb/sqlc/models.go - new generated models for the migration
  • sqldb/sqlc/querier.go - generated querier interface additions
🟠 High (13 files)
  • routing/interval_belief.go - new pathfinding/liquidity-belief logic
  • routing/interval_config.go - interval router configuration
  • routing/interval_pathfind.go - pathfinding algorithm changes
  • routing/interval_session.go - payment session state machine changes
  • routing/interval_session_source.go - session source wiring
  • routing/interval_store.go - interval store abstraction
  • routing/interval_store_sql.go - SQL-backed interval store
  • routing/interval_test_postgres.go - Postgres test harness wiring for the new store
  • routing/interval_test_sqlite.go - SQLite test harness wiring for the new store
  • routing/payment_lifecycle.go - payment lifecycle changes
  • routing/payment_session.go - payment session changes
  • lnrpc/routerrpc/config.go - router RPC config changes
  • lnrpc/routerrpc/routing_config.go - routing config additions
🟡 Medium (1 file)
  • sample-lnd.conf - new sample config options
🟢 Low (12 files)
  • docs/interval_routing.md - new documentation
  • docs/release-notes/release-notes-0.22.0.md - release notes
  • itest/list_on_test.go - itest registration
  • itest/lnd_interval_router_test.go - integration test
  • lnrpc/routerrpc/config_test.go - unit test
  • routing/interval_budget_test.go - unit test
  • routing/interval_inflight_test.go - unit test
  • routing/interval_parallel_test.go - unit test
  • routing/interval_quarantine_test.go - unit test
  • routing/interval_session_test.go - unit test
  • routing/interval_store_sql_test.go - unit test
  • routing/interval_store_test.go - unit test

Analysis

This PR introduces a large new "interval routing" liquidity-belief system spanning routing/*, a new SQL-backed store with an accompanying database migration (sqldb/sqlc/migrations/000016_liquidity_intervals.*), and wiring into server.go. Per policy, database migrations are always classified CRITICAL, and server.go changes are explicitly CRITICAL as core server coordination. The PR also touches 13 HIGH-severity routing/* and lnrpc/routerrpc/* files implementing new pathfinding and payment-session behavior, and would independently qualify for a severity bump given its size (34 files, ~8.9k lines changed, well above the >20 file / >500 line thresholds) — though severity is already at the ceiling. Given the combination of a new persistent schema, payment pathfinding/session logic changes, and core server wiring, this warrants expert review, particularly around correctness of the new liquidity-belief algorithm, migration safety, and interaction with existing payment session state.


To override, add a severity-override-{critical,high,medium,low} label.

In this commit, we add the payment session that owns route selection and
splitting together. The session lnd ships does not choose a shard size:
it asks path finding for the whole remaining amount and halves it when
nothing comes back, so every split is a reaction to a failure and every
shard is a power-of-two fraction. This one enumerates a ladder of
candidate shard sizes, finds a route for each, and keeps the best pairing
of the two, which means it can split before it has failed at all and can
pick a shard sized to fit just under a bound it discovered two attempts
ago.

The ladder draws on four sources: the whole remaining amount and the
smallest shard that could still finish the payment, the amounts this
payment has already proven do not fit divided down until they do, the
even divisions, and the halving chain. The second is what makes the
ladder a function of the beliefs rather than of the amount alone, and it
is enumerated early because every rung costs a full search and the ladder
is capped.

The session layers its own experience over the node wide store. A channel
it watched refuse an amount is discounted by how much smaller the retry
is, on a ladder that replaces blacklisting and waiting for a penalty to
decay. A channel that rejected an HTLC on policy grounds is stepped
around for the rest of the payment, because the policy we hold for it is
stale and a retry would be built from the same stale policy. None of that
outlives the payment, while everything written to the store does.

Two things the session does that the amounts alone would not tell you.
It counts the HTLCs it already has in flight when pricing a hop, since a
channel holding some of ours must have had that much plus the new shard
available when we last looked, and it releases those holds on three
separate triggers so that one can never outlive its HTLC. And when a
failure cannot be attributed to a hop, it narrows the suspects by
elimination rather than penalizing the whole route: one suspect left is a
certainty, none at all is a contradiction, and several share the blame in
proportion to how many there are.

Payments the router does not serve are handed to the stock session
instead, so that turning it on cannot make a payment unroutable that
would otherwise have gone through. Today that means payments to blinded
paths, where there is no directed channel to key a belief on.
In this commit, we make the interval router selectable and leave it off.
The new routerrpc.router option takes either default or interval, and
defaults to default, so a node that says nothing about routing keeps
exactly the stack it had before. With the flag off nothing in the new
code is reached at all: the server builds the same session source it
always did, and the seam the lifecycle grew is a type assertion the stock
session does not satisfy.

The interval source wraps the stock one rather than replacing it, so the
payments the interval router does not serve still get a session that can
route them. Both options are documented in the sample config, along with
the conditions under which the second of them does anything.
In this commit, we let the router keep what it has learned across a
restart. Everything it knows about the network is gathered by attempting
payments, so a cold start is not merely slower, it is paid for in failed
HTLCs until the picture is rebuilt. A new table holds one direction of
one channel per row, the store loads what was written down when the node
starts, and it writes changes back as it goes.

We flush on a ticker rather than writing through. One attempt writes both
directions of every hop it touched, so writing through would put a
handful of database round trips between an HTLC failing and the next
route being chosen, which is the one path in the router a user waits on.
Nothing here has to survive a crash to stay correct either: a belief that
never reached disk is one the router rediscovers on its next attempt, at
the cost of that attempt. The cadence has a knob of its own, so that
tuning it does not mean tuning mission control's as well.

What comes back is deliberately not what went in. A belief read from disk
is marked restored and its confidence halved, and the probability model
then refuses to let either of its bounds speak with certainty. That
matters more here than the same problem would in mission control, because
this model has no clock: a bound moves only when evidence arrives, and an
amount the model calls impossible is never attempted, so the evidence
that would correct a stale bound could never turn up.

Two choices in the schema are worth calling out. Confidence is stored in
parts per million rather than as a float, because nothing else in this
schema has a floating point column and we would rather not be the first
to find out how the two dialects differ on one. And a short channel id of
eight zero bytes is reserved for a belief about a node pair as a whole,
which is the shape the router needs when a pair has several channels and
an observation cannot say which of them carried the payment.

Persistence is only available on a node running the native SQL backend.
Everywhere else the store runs exactly as it did, memory only, with no
dirty tracking and no goroutine.
In this commit, we give the router somewhere to put evidence it cannot
trust. An unreadable onion error, or one that no node on the route
claims, leaves several hops that could each have been the one to refuse.
Writing an upper bound on all of them would be a claim of certainty about
channels that may be perfectly healthy, and a bound in this model is
permanent until evidence moves it: an amount it calls impossible is never
attempted, so a wrong bound can never be corrected.

Ambiguous evidence goes into a quarantine instead, held per directed
channel alongside the interval but deliberately outside it. It keeps the
smallest amount such a failure has named and how much corroboration
stands behind it, where a failure naming two suspects contributes half of
what one naming a single suspect would, so the more ways a failure could
be explained the more of them it takes to convict. While it sits there it
prices as a discount on the amount it named and never as an
impossibility. Enough agreement promotes it into an ordinary upper bound.

What may release a suspicion is the subtle part, and it is narrower than
it first appears. When a hop reports a failure, the router writes a lower
bound on every hop before it, because forwarding is what carried the
payment that far. That inference holds exactly when the report names the
right hop. When blame arrives shifted downstream, which is one of the
ways a real network lies, the guilty channel sits before the reported
index and collects a lower bound saying it carried the amount it had just
refused. A quarantine that accepted lower bounds as proof of innocence
would let that channel out of every suspicion it belonged in and pile the
blame onto its innocent neighbours. So the router keeps a separate record
of what it has watched actually move, written by nothing but a
settlement, and only that clears a suspicion. The lower bound keeps every
other job it has, in path finding and in bound maintenance, and loses
only a standing that was never really its to give.

Three smaller decisions come with it. A settlement proves the direction
it moved over and no other, so the reverse direction is left alone.
Neither the quarantine nor the record of settlements is written to disk,
since a suspicion restored from a previous run is one nothing since could
have cleared, and a settlement from before a restart says nothing about a
failure observed after it. And there is exactly one place anything enters
the quarantine, with a config field on it, so that a node can switch the
whole mechanism off and get the payment-local handling it had before.
In this commit, we exercise the interval router against real nodes. Only
the sender runs it, so the test also covers routing through peers that do
not, which is the situation any node turning this on would be in.

The payment worth testing is the second one. We drain the middle hop,
watch a large payment fail there, and then send a small one without
resetting anything and without waiting. The stock router would have
penalized the node pair on that failure and would need the penalty to
decay before it would offer the pair again. The interval router recorded
an amount rather than a verdict, so every smaller amount over the same
channel stayed routable and the recovery costs one attempt. That is the
behaviour the whole design is for, and the one thing about it an
integration test can show that a unit test cannot.
In this commit, we write down what the router does and why, for a
contributor who knows lnd and has never seen this line of work. The
algorithm inverts the question path finding asks: rather than testing
whether the graph can carry an amount fixed before the search began, it
asks what the network will accept and picks the amount and the route
together. Everything else follows from that, so the document leads with
it.

The rest covers the belief itself, the bimodal prior and why its scale is
a fraction of capacity rather than a number of satoshis, the label
setting search and why a node has to keep more than one answer, how the
shard ladder is priced and where its exchange rate between fees and
reliability comes from, the trust boundary the quarantine draws, and how
all of it coexists with mission control, which keeps running untouched.

The limitations section is the part worth reading twice. It states the
blinded path fallback and what finishing it would take, why a bound
restored from disk is deliberately weaker than one we just watched hold,
why an ambiguous failure is recorded against a node pair rather than a
channel, what the search costs against a single Dijkstra run, and that
the constants in the model were selected by a search rather than derived,
with some of them surely fitted to the simulator that produced them.

The release notes gain an entry under functional enhancements and one
under database, since the router brings a table with it.
@Roasbeef
Roasbeef force-pushed the interval-router-rebased branch from 0da8d1d to e0ced40 Compare August 8, 2026 01:26
@Roasbeef Roasbeef added enhancement Improvements to existing features / behaviour routing labels Aug 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Improvements to existing features / behaviour routing severity-critical Requires expert review - security/consensus critical

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant