Release v0.20.1 - #19
Merged
Merged
Conversation
…he decoder lifecycle harness uses the shared server helper
…push, release and hotfix refs unchanged
Capture the validated source table set during schema reconciliation and report only replicated tables that exist upstream but not locally. Keep unknown source schemas fail-visible and preserve server-side build coverage checks.
… the BTC instant The v0.20.0 family was sized 2026-09-16 20:41Z from last-99-block cadences. LTC testnet then ran at about 82 s per block against the 146.6 s that sizing assumed, pulling its producer boundary to 3.2 h out while BTC's stayed 53.0 h out, and DOGE's drifted 7.5 h early. Two legs of one cross-chain match would have crossed the flag day about two days apart, which is what the same-wall-clock-instant rule exists to prevent. Re-measured 2026-09-17 22:45Z over a trailing window as long as the lead being sized: TBTC 152,891 at 576.7 s per block, TLTC 4,889,190 at 82.5 s, TDOGE 67,904,912 at 27.7 s. BTC is unchanged, still keyed to epoch close 153,216 plus 6 buried; LTC and DOGE are converted onto that same instant, and each consumer is its own producer plus six hours at its own measured cadence rather than a block count carried over from the first sizing. Arms the TRAIN_ACTIVATION 0.20.0 row at testnet 153,116, 106 blocks and about 17 h below the BTC producer. resolveRuleSet reads only the local map, so with no row every block above the boundary keeps resolving under 0.19.0, and a manifest naming 0.20.0 halts a fleet in which no build implements it. Records the cadence-window rule the re-cut used and makes the re-size rule per chain instead of BTC-keyed, so an LTC or DOGE drift past the six-hour ordering margin forces a re-cut the way an overrun BTC height already does.
Move balance helper test registrations into synchronous module-scope helpers while preserving suite order and hook scope. Reduce the two over-limit callbacks without adding await points or changing test coverage.
Extract the hash-continuity cases into bounded module-scope registration helpers. Preserve hook count, test order, titles, assertions, and synchronous scheduling.
Extract the config boundary groups into synchronous module-scope registration helpers. Preserve hook scope, title order, assertions, and zero-yield behavior while lowering the structural finding count.
… ISSUE landed in A valid ISSUE re-derives the whole tokens row from the tick's issues history, so an edit of an existing tick rewrites owner_id, description, the locks, the callback and list fields and the bridge opt-in in place. Both action_index and last_action_index stay pinned at the first issuance, so the action-scoped stream carried the new issues row and never the tokens row it produced, and the only in-place carry keyed on ticks touched by a credit, debit or escrow row. An ownership transfer moves no balance, so every replica served the pre-transfer owner until some later action on the tick happened to move one (xchain-indexer#39: a TDOGE token kept its old owner for 24 blocks, then flipped when an unrelated DESTROY landed). Add the tokens-edit class beside the supply one, keyed on the ticks carrying a valid issues row in the window. Forward only: the reorg direction needs a replica-side re-derive and is registered separately. The 400-line limit put the two tokens classes and the row accumulator into named parts, and the integration proofs for the tokens table into one directory. The registry note is the vendored half of the indexer's canonical edit.
The armed LTC:testnet producer/consumer heights (4891504/4891766) are already behind the live TLTC tip. Ruling dq4 (a), 2026-09-18: LTC:testnet mirror admission ships null on this train and arms on a later train. Sets both heights to null in this repo's shared_rows_2.js twin, with the same replacement comment used across all six carriers.
Propagate the canonical v0.20.1 patch-train reslide into sync's own copy of the shared consensus registry: BTC train height 153221, BTC mirror producer/consumer 153300/153328 (producer also carries ANCHOR_ATTEST_BARRIER_ACTIVATION), DOGE mirror producer/consumer 67916857/67917706. LTC:testnet stays null under dq4 (a) and is untouched. Re-pin bin/pins/identity.json (armed_map_fingerprint and the moved train_activation.TRAIN_ACTIVATION row) to match.
Derive published fixture ports from the gate CI_PORT_OFFSET while preserving zero-offset defaults. Keep container ports fixed and route fixture clients through the same resolved host ports.
Re-vendor src/observability/ from xchain-hub via bin/sync-observability.sh: the canonical module drops its underscore-prefixed method and handle names and corrects stale comments. The test-only reset hook is now resetObservability, so the suite that calls it follows the rename.
Move rebuild parity and client applier coverage into independent integration parts. Share the database hooks and fixtures without changing await counts or title order.
Partition polling, payload, probe, and status coverage into ordered parts. Share polling fixtures and hooks while preserving all nineteen test titles and await counts.
…rollback sweep The twin of the indexer canonical: the note claimed no local pre-delete leg exists while sweeps.js carries one inside the markers.
…ckpoint reads
/halt/clear and the raw server.on('upgrade', ...) guard in api.js ran in no
tier; the armed_source_handshake suite only exercised a hand-transcribed copy
of the upgrade check, which shared safeEqual but not the real handler's
shape. Added a bootRealApi() that proxyquires the real startApi() (network
edges stubbed) and captures the actual upgrade handler off the fake
http.Server, then drives both surfaces directly: /halt/clear's 401 with no
key configured, 401 on a wrong key, and 403 in server mode; the WS guard's
401 on no/wrong key and its pass-through to wss.handleUpgrade on a correct
one.
Also added direct unit coverage for the three state_checkpoints.js reads
(getLatestCheckpoint, findCheckpointsInRange, getCheckpointAtHeight), which
had none: each is asserted against its literal SQL shape, its bound params
(including the caller-supplied LIMIT), and an empty-result response.
… absent sibling, correct the drain comment
… bound after bootstrap, fail closed on block-hash reads The reconcile cadence knobs come from config, the wall-clock bound arms after a full-snapshot bootstrap, BlockHasher fails closed on a read error, decoder events leave content parity, pubkeys honor skip_lookups, the decoder scoping sets derive from TOPOLOGY, and the snapshot-dispensers route docs match the stream.
…in and reference-impl headers
…d a cross-source markets id parity tool A same-target duplicate-key failure that repeats now sets a visible halt with its reason instead of retrying forever, and bin/markets-id-parity.js compares markets ids by ticker across two sync sources. Stale lifecycle comments are corrected.
…e-copy the table-lifecycle twin reconcileDispensers now refuses a page whose schema_version does not match the replica before collecting rows, so a version-mismatched follower no longer replaces its dispensers table from the status tick.
…the checkpoint reads
… margin Live testnet tips (TBTC 153698, TDOGE 67924122 at 2026-09-23T15:55Z) have passed every height the 2026-09-19 reslide armed, so the freeze preflight refuses them. The operator ruled a second reslide to 40 h of margin to the nearest armed height at the fastest defensible cadence (BTC least-squares bound 383.04 s/block, DOGE median 11 s/block), keeping the prior spacing. Propagate it into sync's own copy of the shared consensus registry: BTC train height 154074 (tip + 376 blocks, 40 h), BTC mirror producer/consumer 154234/154291 (train + 160, 17 h; producer + 57, 6 h; the consumer also carries ANCHOR_ATTEST_BARRIER_ACTIVATION), DOGE mirror producer/consumer 67942777/67944741 (tip + 18655, 57 h, the same instant as the BTC producer; producer + 1964, 6 h). LTC:testnet stays null under dq4 (a) and is untouched. Re-pin bin/pins/identity.json (armed_map_fingerprint and the moved train_activation.TRAIN_ACTIVATION row) to match, regenerated with bin/pin-identity.js --out.
Replace the opaque dq4 (a) decision label and an issue-tracker id with self-contained public rationale. Comment text only; the table-lifecycle twin stays byte-identical to xchain-indexer's canonical copy, and the shared gate rows stay byte-identical to the other five carriers.
…n reorg Updated-rows class 7 carries an ISSUE edit's tokens row forward, but a reorg that orphaned the edit left the replica on the edited row while the source refolded it from the surviving issues (rollback/commit.js updateTokens). The row's action_index is the first issuance, so the generic delete never touched it and no later window re-sent it: a silent replica divergence on owner, the seven locks, callback, lists, mint window and bridge policy. ClientRollback now collects every tick the orphaned range issued on before the delete and, after it and before the supply recompute, rewrites each tick's fold columns from its surviving valid issues inside the rollback transaction. The port (src/db/token_refold.js) restates getTokenInfo's replay and createToken's normalize and fields step for step; a tick whose first issuance is not held locally (truncated replica) is skipped and logged rather than folded from a tail. The fold columns sat in no hash, so an advisory TOKEN_FOLD_PARITY_CHECK (default off, never halts) now digests them on /status and at the follower's bootstrap cross-check, bounded on the source by the published height's last action. Tests run each reorg (ownership, lock, bridge policy, callback/list/mint window) against the xchain-indexer's own fold when the sibling is present.
…iling mean Operator ruling D11 (a) 2026-09-23: producer moves from 67942777 to 67936053 and consumer from 67944741 to 67936888, the same-instant rule computed off the 84h trailing block-time mean. BTC:testnet heights are unchanged; their comments now also carry the 84h trailing mean cadence bound. Byte-identical to the other five shared-row carriers; sync's own bin/pins/identity.json does not track this gate and is unchanged.
This was referenced Sep 23, 2026
The floating node:22-bookworm tag can move to a Node patch whose V8/ICU no longer match xchain-vm's consensus runtime pin, so validators built from it would fail to join the fleet. Pinning by digest to a measured match removes that risk.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release v0.20.1
Coordinated platform release across the 13-repo v0.20.1 train.
masterrelease/v0.20.1What changes
153221to154074, with BTC producer/consumer activation at154234/154291, DOGE producer/consumer activation at67942777/67944741, andANCHOR_ATTEST_BARRIER_ACTIVATIONat154291;LTC:testnetmirror admission remainsnullunder dq4 (a).schema_versionon every dispenser reconciliation page, fills the reconciliation controls, and fails closed on block-hash reads.Sibling release PRs
Filled in by open-release-prs.sh --execute once every PR above has a number: