v3.1.0
A security update, two production defects that only measurement could have found, and a sprint's worth
of gates that turned out not to be gating anything.
Security
wasmtime 46.0.3 - RUSTSEC-2026-0268 and RUSTSEC-2026-0269. Reason enough on its own to take this
release.
Two defects that were live in production
Both were invisible to code-reading and obvious the moment anything was measured against a running
nest. Both are the same shape - a surface reporting something the system did not believe.
tip_lag_blocks read 0 on a nest that was behind (#1020). The gauge was written from a
process-global rather than the nest's own metrics, so a lagging nest published a healthy lag and no
alert could ever fire. The one number an operator watches to know the indexer is keeping up was the
one number that could not tell them it wasn't.
A read-only nest reported ready:false forever (#1025). Readiness folded in a staleness check on
the tip poll - and a nest served without a cursor, by design, never polls. So nuthatch serve on
sealed history was permanently unready, which is a load balancer's instruction to take it out of
rotation. The verdict now excludes the cursor leg when there is no cursor.
They are mirror images: one said healthy when it was not, the other said unhealthy when it was fine.
Behaviour worth knowing before you upgrade
Seal boundaries no longer depend on --window (#1015). Segment layout for new seals differs
from what a 3.0.1 nest would have produced. Sealed segments are immutable and nothing on disk is
rewritten, so this is forward-only - but it is the thing to watch after the first restart.
A parameter that shadows an implicit column is now refused at startup (#1038). address,
table, _seq, block_number, block_hash, block_timestamp, tx_hash, log_index. A config
that collided previously produced a silently wrong column; it now refuses to start. Validate your
configs against the new binary before restarting a running nest.
/balances and /balance/{address} carry dropped_over_i128 (#1043). A balance that omitted a
transfer too large for i128 used to say nothing about it. It now says so, in its own field, rather
than quietly answering with a number that is wrong by an unknown amount.
Two new environment variables, both defaulting to today's behaviour and changing nothing until
set. NUTHATCH_SQL_MAX_CONCURRENCY (#1006) and NUTHATCH_HOT_STORE_CACHE_BYTES (#1046) exist so
their values can be measured on the box that enforces the RAM budget, rather than set from whichever
machine was convenient.
What we learned about our own gates
The recurring finding of this sprint, stated plainly because it kept happening: a test that passes
proves nothing until it has been made to fail. Among the gates that were green while guarding
nothing - a documentation check whose glob excluded the very file its comment warned about (#1027), an
ABI-floor test that could not tell the fixed README from the broken one (#1026), a tip-lag test
asserting an internal getter rather than the gauge an operator reads (#1028), and a concurrency test
whose two locks on one environment variable excluded each other not at all (#1035).
Measurement that changed a decision
RFC-0042 is parked: KEEP DuckDB, at 78% confidence on six measured regressions, with a reopen date
of 2027-09-01 and four triggers.
#296, compact binary rows, was closed against the change. A prototype encoder found that hot-store
RSS does not track the file at all - it tracks redb's cache size, which nuthatch had never set. At
every cache size below both files, a JSON store and a compact store land on identical RSS across a
2.00x file difference. The ~750 MB per cursor the issue was justified by is available for one argument
at three call sites, with no format change and no part of RFC-0020's no-resync promise spent.
The Tier-B agent eval has a published baseline: 0/15, verified rather than accepted - all fifteen
known-correct oracles score as passes through the runner's own path, so the zero belongs to the agent
and not the harness.
No data migration. A binary swap and a restart, as ever - with the two caveats above.