Skip to content

Release v0.20.0 - #15

Merged
jdogresorg merged 23 commits into
masterfrom
release/v0.20.0
Sep 18, 2026
Merged

jdogresorg merged 23 commits into
masterfrom
release/v0.20.0

Conversation

@jdogresorg

@jdogresorg jdogresorg commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Title: Release v0.20.0

Summary

Added

  • Added acceptance coverage for mirror-admission and anchor-attestation barriers across live, replay, flag-day, parity, and second-chain cases.
  • Added end-to-end token-bridge and policy-inheritance rail suites for regtest.

Changed

  • Each test chain now uses its own fee destination.
  • DOGE cross-settle setup is seeded from the disclosed mirror topology.
  • Bridged-gas tests resolve the hub relay-margin table from the sibling checkout.
  • Bridged-gas tests wait for the relay margin while both chains idle-mine.

Fixed

  • Action drills follow the relocated writer-leg resolver.
  • Database helpers no longer expose the unused sqlPath field.
  • Barrier drills wait for required state instead of fixed delays.
  • Replay drives safely serialize database rows that contain BigInt values.

Sibling release PRs

Merge order

Merge order: merge after xchain-explorer and before xchain-sdk.

CI note

GitHub CI on this branch clones sibling repos at develop, not at this release branch, unless a workflow call passes siblings-ref for release branches. A cross-repo guard failure here can reflect that develop-only comparison rather than a real disagreement with a sibling still on this release branch; check the venue pre-push gate (which ships each companion at its own release branch) before treating a red guard as a defect.

…s at the src/consensus tails from the indexer's bytes, citations and requirers repointed (activation registry row 21c)
…ts own fee address

nativeFeeHelper.resolveFeeDestination reads the generic FEE_DESTINATION env
before it asks the indexer, and an xchain-node e2e container sets it to the LEG
coin's address. withRail did not swap it, so every fee output injected on the
second chain paid the first chain's destination. Measured on the first two-stack
litecoin matrix leg (xchain-node run 35111751698): the BTC gas lock paid LTC's
regtest destination, the BTC indexer saw no fee output, fell back to
XCHAIN-balance mode and refused the lock with `insufficient funds (FEE)`.

FEE_DESTINATION joins RAIL_ENV. createRail resolves it on the credential ladder
(<CODE>_FEE_DESTINATION, then .env.<code>) and otherwise leaves it undefined,
which enterRail turns into a delete for the duration of the swap, so the helpers
discover that chain's destination from its own feeschedule. exitRail and
captureCurrentRail carry the leg coin's value back.
…n the bitcoin leg

The v0.19.0 freeze matrix bitcoin leg (run 35102834217) read 269 passing,
32 pending, 4 failing against the last green leg's 273 / 32 / 0, and all four
are harness drift from the structure passes. The unstaked-signature case in
attestation.test.js lost `contractIndex` from its destructure when the suite
was split (ReferenceError at line 174). The delegated-reward drill's minimal
db adapter mirrored the indexer's Database, but the indexer pass moved the
resolver's two SQL legs into named mixins (indexer 0bb77814) that the resolver
now calls on the db it is handed, so every resolution died inside the resolver
as "failed to resolve stake source"; the adapter carries both methods now,
SQL byte-identical to src/db/stakes/credit_source_reads.js and
src/db/delegations/index.js.

(cherry picked from commit 1a1e310)
…e delegated-reward drill

The targeted re-run (35126895624) cleared three of the four cases and left
the slash-exclusion case dying on `_resolveActiveStakeSourceId`, which the
indexer structure pass renamed to resolveActiveStakeSourceId when it dropped
underscore methods; the drill calls the master mixin by its current name.

(cherry picked from commit dd0702a)
The lock now records the hub and sdk devDependency trees (eslint and its
acorn/@eslint tree) that the image npm ci resolves through the file: links.

(cherry picked from commit 4277bde)
… with both chains idle-mining

bridgeGasIn waited 120 s for the bridged XCHAIN credit, but the hub stamps a
finalized transfer with effective_time = now + relayMarginFloorS(dest) (LTC
600 s, DOGE 240 s) and the destination indexer settles the credit only once the
chain's protocol time (median-time-past off mainnet) passes that instant, so no
120 s wait could ever see it. Neither regtest miner mines without a transaction
in its mempool either, so with nothing in flight BTC never buried the lock to the
hub's depth and the destination clock never moved (nightly two-stack legs, runs
35122297316 and 35124072478: "not proposing BTC:3 (below depth 6)", then
"checkCredit: GAVE UP after 120202ms").

The wait is now the destination's relay margin, read from the bundled xchain-hub
copy, plus 180 s slack, and the whole gas-in runs with a 10 s idle heartbeat on
the BTC rail's miner and on the destination's standing miner, switched back off
in a finally on every exit path because the rest of the suite counts blocks.
… only through the file: dep

The venue gate's staged checkout carries no node_modules link for the hub
sibling, so the bare package require died at load ("Cannot find module
'xchain-hub/src/lib/relay_margin'") and took the whole unit tier with it.
gasHelper now resolves the table the way multiValidatorHubHelper resolves the
hub source: the file: dep first, then the copy staged beside the package in
the e2e image, then the monorepo sibling, then the xchain-node modules/
layout, and fails loud naming every path it tried.
…ology

The three DOGE setup drivers now ask the indexer where its price reads
actually land (hubMirrorTopology.resolveDriverPriceTarget) instead of
assuming HUB_DB_NAME, so a mirror-topology venue seeds the database the
indexer reads rather than one hub_db_sync's insert-only cursor can never
carry the upsert/delete shape across. The two settle drills resolve the
relay hub's own database through a new relayHubParams helper (preferring
HUB_SOURCE_DB_NAME) instead of reusing HUB_DB_NAME, which on a mirror
venue names an indexer's database rather than the hub's.
constructor pointed this.sqlPath at a __dirname-rooted src/sql that
does not exist in this repo, and nothing anywhere reads the field
(grep across the repo and the platform tree found only the same
unread assignment in the xchain-node vendored twin). Deleted rather
than creating the directory: row 78/79 path-resolution sweep.
On a pull_request event github.ref is refs/pull/<n>/merge, so the old
master arm could never fire and every PR into master graded against
develop siblings. This repo's PR trigger is master-only, so that was
every PR it runs.
…barrier family

Adds the bf1-bf8 barrier drills and the ab1-ab5 anchor-attest drills with their
fixture, row and drive helpers, extends the attest-mirror venue to arm the
family, and widens test:attest-mirror to run the new directory.

Platform buildout row 15 (child rows 7, 8, 9b, 10, 11 and three seam-fix passes).
…ndexer per venue hub

Carries the token suite with its four driven harness patches, adds the policy suite for AT1 to AT10, gives each venue hub its own BTC indexer so retractions co-sign as in production, and refuses a venue that would fall back to the standing indexer.
…ck, funding the BF1 marker before the hold

A block mined between the tip read and the drill block parked the barrier walker on the wrong height, so bf1 timed out with an empty walk on every rail run. The hold pauses, levels every indexer to the tip, and resumes only on the drill block or in after hooks.
…ded XDEX rounds, and keep BF2's legacy rows out of the bridge and policy apply passes
…3 order, BF1 oracle row and BF6 seated pair; judge BF1's walker class per deadline; BF2 waits for published heights
…internal spec paths

Reword the drive banners in bridge_rail_policy.test.js and
bridge_rail_token.test.js to name acceptance sections and decisions
without an internal spec path. Comment-only change; no behaviour moves.
…chain can publish

The hub publishes an admission-height watermark at most one below its own
observed tip, so a member with a small margin can never reach its plain
B - margin line while the leg holds the chain at B-1. Add a clamp helper
next to the existing admission-height wait and switch BF2's pre-mining
wait to it, so a low-margin member waits at the height a held chain can
actually publish instead of one it can never produce. A unit test proves
the clamp directly and a behavioral test proves the wait resolves where
the unclamped line would hang.
…era mirror corpus for the replay witness

Add at4_signed_admission_corpus: seats an adoptable roster with the roster
seeder when the chain has none, runs AT1's http_get request on a venue armed
through bootFamilyVenue (hubs and both indexers), asserts the signed mirror
row carries admit_block_btc and both indexers apply it with no transaction at
that height, then levels past it and prints the replay witness command.

Pure helpers (request contract, admitted-at-height apply findings, witness
command with H between the admission height and the corpus tip) live in
barrierFamilyRows; the mirror read, corpus coordinates and an xchain-vm link
check that names a dangling link before boot live in barrierFamilyDrive.
…ixed sleeps

Replaces the three fixed-settle waits commit 1adcd49 added (AB3's hold
observation, BF8's LTC stamp gap, and spaceChainBehindMargin's horizon
wait) with bounded condition waits on the mirrorDrillWaits `until` poller,
so scripts/check-sleep-flake.js reads 31 again instead of 34. No
assertion's meaning changed.
…fe serializer

Adds bigintSafeStringify to barrierFamilyRows.js and uses it at the three JSON.stringify call sites in the AT4 corpus test so mariadb BIGINT columns no longer throw before the witness command prints.
@jdogresorg
jdogresorg merged commit 469bd3e into master Sep 18, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant