diff --git a/CHANGELOG.md b/CHANGELOG.md index 666a2b2e..01e24357 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.20.0] - 2026-09-17 + +### Changed +- The vendored registry includes shipped mirror-admission and anchor-attestation barrier heights. +- `carrier_logic_pin_ops --move` can re-pin changed carrier logic and record path and hash transitions atomically. +- Activation modules and fingerprint tooling follow the consolidated consensus layout. + ## [0.19.1] - 2026-09-16 ### Fixed diff --git a/README.md b/README.md index dcfd0a38..196dd717 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ # XChain Sync

- Version + Version Tests Node License diff --git a/bin/lib/carrier_logic_pin_ops.js b/bin/lib/carrier_logic_pin_ops.js index 7bae09f8..d4dfb6e9 100644 --- a/bin/lib/carrier_logic_pin_ops.js +++ b/bin/lib/carrier_logic_pin_ops.js @@ -146,11 +146,17 @@ module.exports = function carrierLogicPinOps(core) { * activation file at the top level and under src/lib, every SHARED_GATES * carrier at src/.js, and the digest module that computes the requires. */ - function hubMembers(dir) { + function hubMembers(dir, pin) { const source = fs.readFileSync(path.join(dir, 'src/consensus_rules_digest.js'), 'utf8'); - const shared = constInit(source, 'SHARED_GATES').elements - .map((row) => `src/${row.elements[0].value}.js`); - return activationFiles(dir).concat(activationFiles(dir, 'lib'), shared, ['src/consensus_rules_digest.js']) + // A SHARED_GATES stem lives at its pinned path once W5 has moved it + // (src/consensus/gates/_gate.js, src/consensus/.js or a + // hub-owned home such as src/attestation/); the pin already records + // that path per id, so read it there rather than restating the loader's + // move table. A stem with no pin entry yet (before --init) falls back + // to the pre-W5 flat path. + const ids = Array.from(new Set(constInit(source, 'SHARED_GATES').elements.map((row) => row.elements[0].value))); + const shared = ids.map((id) => (pin && pin.entries && pin.entries[id] ? pin.entries[id].path : `src/${id}.js`)); + return activationFiles(dir).concat(activationFiles(dir, 'lib'), gateFiles(dir), shared, ['src/consensus_rules_digest.js']) .filter((rel) => fs.existsSync(path.join(dir, rel))); } @@ -171,9 +177,9 @@ module.exports = function carrierLogicPinOps(core) { .concat(gateFiles(dir), fixedCarrierPaths(dir, pin, FIXED_CARRIER_IDS[name]), ['src/consensus_rules_digest.js']) .filter((rel) => fs.existsSync(path.join(dir, rel))); } else if (name === 'xchain-sync') { - list = activationFiles(dir).concat(fixedCarrierPaths(dir, pin, FIXED_CARRIER_IDS[name])); + list = activationFiles(dir).concat(gateFiles(dir), fixedCarrierPaths(dir, pin, FIXED_CARRIER_IDS[name])); } else if (name === 'xchain-hub') { - list = hubMembers(dir); + list = hubMembers(dir, pin); } else { throw new Error(`no membership rule for ${name}`); } @@ -245,9 +251,8 @@ module.exports = function carrierLogicPinOps(core) { } /** - * Repoint one entry at `rel`, keeping its id and hash. Refused, as a logic - * finding (exit 1), when the file at the new path hashes differently: a move - * carries the module, never a change to it, which goes through --write. + * Repoint one entry at `rel`, keeping its id. A changed hash is accepted + * only with a reason, and the one move record then proves both changes. */ function moveEntry(dir, pin, id, rel, reason) { const before = pin.entries[id]; @@ -255,12 +260,12 @@ module.exports = function carrierLogicPinOps(core) { if (before.path === rel) throw new Error(`${id} is already at ${rel}; nothing to move`); const hash = hashFile(dir, rel); if (hash === null) throw new Error(`${rel} does not exist under ${dir}`); - if (hash !== before.hash) { - const err = new Error(`${id}: the logic at ${rel} (${hash.slice(0, 8)}) is not the pinned logic (${before.hash.slice(0, 8)}); a move carries a module unchanged, re-pin a changed one with --write`); + if (hash !== before.hash && (typeof reason !== 'string' || reason.trim() === '')) { + const err = new Error(`${id}: moving to changed logic requires --reason`); err.exitCode = 1; throw err; } - pin.entries[id] = Object.assign({}, before, { path: rel }); + pin.entries[id] = Object.assign({}, before, { path: rel, hash }); const record = { id, from: before.hash, to: hash, path: { from: before.path, to: rel }, date: today() }; if (reason !== undefined) record.reason = reason; pin.repins.push(record); @@ -270,7 +275,8 @@ module.exports = function carrierLogicPinOps(core) { * Every difference between the pin as committed and `pin` that carries no * `repins` record of the right shape: a changed or added hash needs a record * whose `to` is the new hash, a retired id one whose `to` is null, and a - * moved path one whose `path.to` is the new path under the unchanged hash. + * moved path one whose `path.to` is the new path. A hash-and-path move needs + * one record whose hash and path fields prove both the old and new states. * @returns {string[]} `: ` lines, empty when every change is recorded */ function unrecordedChanges(committed, pin) { @@ -285,6 +291,12 @@ module.exports = function carrierLogicPinOps(core) { } continue; } + if (before && before.path !== rel) { + const combined = repins.some((r) => r.id === id && r.from === before.hash && r.to === hash && + r.path && r.path.from === before.path && r.path.to === rel); + if (!combined) out.push(`${id}: hash and path changed with no combined --move record`); + continue; + } if (!repins.some((r) => r.id === id && r.to === hash)) { out.push(`${id}: ${before ? 'hash changed' : 'added'} with no --write or --add record`); } @@ -343,8 +355,10 @@ module.exports = function carrierLogicPinOps(core) { } writePin(dir, pin); const rec = pin.repins[pin.repins.length - 1]; - if (verb === 'moved') console.log(`moved ${opts.id}: ${rec.path.from} -> ${rec.path.to} (${rec.to.slice(0, 8)} unchanged)`); - else if (verb === 'retired') console.log(`retired ${opts.id}: ${rec.from} -> (gone)`); + if (verb === 'moved') { + const hashMove = rec.from === rec.to ? `${rec.to.slice(0, 8)} unchanged` : `${rec.from.slice(0, 8)} -> ${rec.to.slice(0, 8)}`; + console.log(`moved ${opts.id}: ${rec.path.from} -> ${rec.path.to} (${hashMove})`); + } else if (verb === 'retired') console.log(`retired ${opts.id}: ${rec.from} -> (gone)`); else console.log(`${verb} ${opts.id}: ${rec.from || '(new)'} -> ${rec.to}`); return 0; } diff --git a/bin/pin-identity.js b/bin/pin-identity.js index fc560d95..8a57aa92 100644 --- a/bin/pin-identity.js +++ b/bin/pin-identity.js @@ -64,13 +64,14 @@ function sha256(rel) { /** The whole identity of this build, as the pin stores it. */ function buildPin() { - const v2 = require(path.join(REPO_ROOT, 'src/consensus/armed_map/fingerprint_v2.js')).computeArmedMapFingerprintV2(); + const v2 = require(path.join(REPO_ROOT, 'src/consensus/armed_map/fingerprint.js')).computeArmedMapFingerprintV2(); const logicPin = require(path.join(REPO_ROOT, 'bin/lib/carrier_logic_pin.js')); const coins = {}; for (const rel of COIN_FILES) coins[rel] = sha256(rel); return { + // The legacy field carries v2 and the version field says so; the _v2 alias of the + // W1 to W4 window left the pin at W5 (activation-registry C4, D103). armed_map_fingerprint: v2.hex, - armed_map_fingerprint_v2: v2.hex, armed_map_fingerprint_version: 2, armedMapRows: v2.rows || null, armed_map_rows: v2.count === undefined ? null : v2.count, @@ -82,8 +83,7 @@ function buildPin() { /** Pin against tree, field by field, so a failure names the file that moved. */ function compare(pin, fresh) { const differences = []; - for (const field of ['armed_map_fingerprint', 'armed_map_fingerprint_v2', - 'armed_map_fingerprint_version', 'armed_map_rows', 'carrier_logic_digest']) { + for (const field of ['armed_map_fingerprint', 'armed_map_fingerprint_version', 'armed_map_rows', 'carrier_logic_digest']) { if (pin[field] !== fresh[field]) differences.push(`${field} ${pin[field]} became ${fresh[field]}`); } for (const group of ['armedMapRows', 'vendoredCoins']) { @@ -97,6 +97,11 @@ function compare(pin, fresh) { else differences.push(`${group}: ${name} changed bytes`); } } + // A pin field this tool no longer writes (the W1 to W4 _v2 alias, or any future + // retirement) is a pin taken by an older tool: it does not hold until re-pinned. + for (const field of Object.keys(pin)) { + if (!Object.prototype.hasOwnProperty.call(fresh, field)) differences.push(`${field} is no longer recorded; re-pin`); + } return differences; } @@ -143,7 +148,6 @@ function main() { } console.log(`armed-map fingerprint ${fresh.armed_map_fingerprint}`); console.log(`armed-map version ${fresh.armed_map_fingerprint_version}`); - console.log(`armed-map v2 ${fresh.armed_map_fingerprint_v2}`); console.log(`armed-map v2 rows ${fresh.armed_map_rows}`); console.log(`carrier logic digest ${fresh.carrier_logic_digest}`); console.log(`vendored coin files ${Object.keys(fresh.vendoredCoins).length}`); diff --git a/bin/pins/at1-suite-titles.json b/bin/pins/at1-suite-titles.json index cf6c1c87..42f4593e 100644 --- a/bin/pins/at1-suite-titles.json +++ b/bin/pins/at1-suite-titles.json @@ -5,6 +5,31 @@ "replicated DATETIME columns depend on db.js dateStrings:true @regression decoder: the wire-replicated DATETIME/TIMESTAMP inventory matches the frozen list", "replicated DATETIME columns depend on db.js dateStrings:true @regression indexer: the wire-replicated DATETIME/TIMESTAMP inventory matches the frozen list" ], + "00ce7fb476e3182e": [ + "Tier 2 - ServerPoller @tier2 buildBlockPayload never throws when DB returns fuzzed row objects", + "Tier 2 - ServerPoller @tier2 buildBlockPayload never throws when all DB methods resolve normally", + "Tier 2 - ServerPoller @tier2 buildBlockPayload never throws when individual DB table reads throw", + "Tier 2 - ServerPoller @tier2 buildBlockPayload payload always has correct top-level shape", + "Tier 2 - ServerPoller @tier2 buildBlockPayload returns null when getBlockHashRow returns null" + ], + "0193b2edcc8a3f28": [ + "Advisory table-content parity wiring case 7: the advisory check never halts", + "Advisory table-content parity wiring feeds the source's window and id ceilings back into the local recompute", + "Advisory table-content parity wiring is wired into the decoder path too, which has no hashes at all", + "Advisory table-content parity wiring runs only at the source's published height, behind the flag", + "Advisory table-content parity wiring the /status producer publishes the payload for both dbTypes, default null" + ], + "01a0e95347ac133b": [ + "Integration: ClientRollback balance recalculation excludes zero-balance entries", + "Integration: ClientRollback balance recalculation rebuilds balances from remaining credits/debits", + "Integration: ClientRollback rollback deletes correct rows removes actions with action_index >= firstActionIndex", + "Integration: ClientRollback rollback deletes correct rows removes blocks at and after rollback point", + "Integration: ClientRollback rollback deletes correct rows removes credits with action_index >= firstActionIndex", + "Integration: ClientRollback rollback deletes correct rows removes sync_meta entries at and after rollback point", + "Integration: ClientRollback rollback deletes correct rows removes transactions at and after rollback point", + "Integration: ClientRollback rollback then re-sync allows new data to be applied after rollback", + "Integration: ClientRollback rollback with no actions handles block with no actions cleanly" + ], "01f9d7edc3706d8a": [ "Boundary: Poll Loop Limit (100 blocks) caps at 100 blocks when 101 available", "Boundary: Poll Loop Limit (100 blocks) caps at 100 blocks when 200 available", @@ -14,22 +39,66 @@ "Boundary: Poll Loop Limit (100 blocks) processes exactly 99 blocks in one poll", "Boundary: Poll Loop Limit (100 blocks) processes remaining 1 block on second poll after cap" ], + "0351fed12642c8a1": [ + "ClientSync: runIncrementalCatchUp aborts the pass (no request, no apply) when the tip read faults", + "ClientSync: runIncrementalCatchUp happy path: dbTip null \u2192 sinceBlock=1, calls applyIncrementalSnapshot", + "ClientSync: runIncrementalCatchUp happy path: dbTip=10 \u2192 sinceBlock=11", + "ClientSync: runIncrementalCatchUp logs error when axios.get rejects", + "ClientSync: runIncrementalCatchUp reads the resume cursor fail-CLOSED (opts.rethrow)", + "ClientSync: runIncrementalCatchUp returns early when no sources configured" + ], "03d0b8b6f4107f85": [ "sync boot consensus-pin verification halts startApi fail-closed on a pin mismatch, before any express app", "sync boot consensus-pin verification passes on the vendored bundle for every network", "sync boot consensus-pin verification skips on the (currently null) mainnet pin", "sync boot consensus-pin verification the pin check runs before the express app is built" ], - "042207350fe3ef68": [ - "armed map v2: falsification on temp trees a copied tree reads the same v2 as this checkout, so the harness measures the real thing", - "armed map v2: falsification on temp trees a deleted manifest row moves v2 and turns the completeness suite red", - "armed map v2: falsification on temp trees a value the canonicaliser refuses reads UNREADABLE", - "armed map v2: falsification on temp trees an export that vanishes from a carrier reads UNREADABLE and names the row", - "armed map v2: falsification on temp trees does not move under the regtest venue arming environment (no sync carrier reads it)", - "armed map v2: falsification on temp trees holds under a comment, a reformat, a rename and a move with only the manifest repointed", - "armed map v2: falsification on temp trees moves when NOT-YET-PINNED (null) becomes the UNARMED sentinel", - "armed map v2: falsification on temp trees moves when one committed height changes, and names that row alone", - "armed map v2: falsification on temp trees without node_modules reads UNREADABLE, never a plausible hex" + "05a50fe7a5a97bc8": [ + "API security createApiKeyMiddleware passes through when no API key is configured (empty string, open mode)", + "API security createApiKeyMiddleware passes through when no API key is configured (null, open mode)", + "API security createApiKeyMiddleware passes through when no API key is configured (undefined, open mode)", + "API security createApiKeyMiddleware passes through with correct Bearer token", + "API security createApiKeyMiddleware rejects key with extra whitespace", + "API security createApiKeyMiddleware rejects partial key match", + "API security createApiKeyMiddleware returns 401 when API key is set but no Authorization header", + "API security createApiKeyMiddleware returns 401 when API key is set but wrong key", + "API security createApiKeyMiddleware returns 401 when header has Basic auth instead of Bearer", + "API security createApiKeyMiddleware returns 401 when header present but no Bearer prefix", + "API security error response sanitization API error responses should use generic message pattern", + "API security error response sanitization Internal server error message does not vary by exception type", + "API security safeEqual false for a length mismatch (prefix of the key)", + "API security safeEqual false for a one-character difference of equal length", + "API security safeEqual false when either side is null or undefined", + "API security safeEqual true for identical strings", + "API security safeEqual true for two empty/absent values (both coerce to empty)" + ], + "068103cacb04749f": [ + "ClientSync security handleReorg: max rollback depth HALTS (fails closed) when reorg exceeds MAX_ROLLBACK_DEPTH", + "ClientSync security handleReorg: max rollback depth HALTS on deep rollback to block 1", + "ClientSync security handleReorg: max rollback depth HALTS the decoder track too (no recompute safety net)", + "ClientSync security handleReorg: max rollback depth allows rollback of depth 1", + "ClientSync security handleReorg: max rollback depth allows rollback within MAX_ROLLBACK_DEPTH", + "ClientSync security handleReorg: max rollback depth ignores a reorg when lastAppliedBlock is null (no cursor inflation from server data)" + ], + "07d974594667f5bb": [ + "ClientApplier: anchor_actions bundle sections inserts every section of a bundle, naming section_index in the write", + "ClientApplier: anchor_actions bundle sections leaves anchor_actions on a plain INSERT, so a section collision cannot pass silently" + ], + "07fa9a8166b63715": [ + "XCHAIN_ESC locked leaf: arming moves balances_root @regression an armed height adds locked leaves the inert height does not have", + "XCHAIN_ESC locked leaf: delete-on-zero @regression NULL, empty and canonical zero are all \"no leaf\"", + "XCHAIN_ESC locked leaf: delete-on-zero @regression a fully filled order returns the tree to its pre-lock root", + "XCHAIN_ESC locked leaf: delete-on-zero @regression a negative total throws rather than committing (writer bug, not a state)", + "XCHAIN_ESC locked leaf: delete-on-zero @regression a nonzero total is amountLeaf, the same encoding the spendable leaf uses", + "XCHAIN_ESC locked leaf: inertness @regression a full rebuild with NO height argument keeps the v1 leaf set (fail closed)", + "XCHAIN_ESC locked leaf: inertness @regression an inert chain issues ZERO journal queries from the full rebuild", + "XCHAIN_ESC locked leaf: inertness @regression is inert on every chain, network and height EXCEPT the armed one", + "XCHAIN_ESC locked leaf: inertness @regression the ARMED height DOES read the journal (the gate really opened)", + "XCHAIN_ESC locked leaf: journal reads @regression MAX(id) runs over releases too: a released lock stays released", + "XCHAIN_ESC locked leaf: journal reads @regression an orphaned journal row reverts with no repair pass", + "XCHAIN_ESC locked leaf: journal reads @regression as-of-height reads serve the value the checkpoint committed", + "XCHAIN_ESC locked leaf: journal reads @regression incremental application equals a full rebuild of the same live set", + "XCHAIN_ESC locked leaf: journal reads @regression the touched set is per LOCKER, and only for blocks that changed a total" ], "091ee0965b4ff600": [ "consensus-primitive conformance: byte-identity to canonical source @regression equivocation_header.js is byte-identical to xchain-documentation/protocol/reference-impl", @@ -113,84 +182,61 @@ "TransparencyLog recordBlock does not commit an epoch for block 0", "TransparencyLog recordBlock swallows a commitEpoch error so recordBlock still resolves" ], - "0acdc71d34c76fe1": [ - "ClientApplier _insertRows attest_validator_stats surrogate id (strip-only class) issues no DELETE: the natural key is composite and a scoped delete would drop siblings", - "ClientApplier _insertRows attest_validator_stats surrogate id (strip-only class) leaves a row that carries no id alone", - "ClientApplier _insertRows attest_validator_stats surrogate id (strip-only class) refuses a row that carries only the stripped id rather than inserting nothing", - "ClientApplier _insertRows attest_validator_stats surrogate id (strip-only class) still upserts on the natural key, so a re-dump refreshes the counters", - "ClientApplier _insertRows attest_validator_stats surrogate id (strip-only class) strips the source id so the replica keeps its own", - "ClientApplier _insertRows backtick-wraps column names", - "ClientApplier _insertRows batches inserts in groups of 100", - "ClientApplier _insertRows blocks surrogate id (item 808) deletes the existing row for that block_index first, so a re-send is idempotent", - "ClientApplier _insertRows blocks surrogate id (item 808) does not use IGNORE or UPSERT, which would drop or overwrite a block", - "ClientApplier _insertRows blocks surrogate id (item 808) fails closed on a row with no block_index rather than appending a duplicate", - "ClientApplier _insertRows blocks surrogate id (item 808) leaves a legacy row that carries no id untouched", - "ClientApplier _insertRows blocks surrogate id (item 808) scopes the delete to the applied blocks only, never the whole table", - "ClientApplier _insertRows blocks surrogate id (item 808) strips the source id so the replica assigns its own", - "ClientApplier _insertRows does nothing for empty rows", - "ClientApplier _insertRows does nothing for null rows", - "ClientApplier _insertRows handles null column values", - "ClientApplier _insertRows handles undefined column values as null", - "ClientApplier _insertRows keeps refreshing markets.id, whose id space is source-assigned end to end", - "ClientApplier _insertRows throws on an invalid column name without querying (fail closed)", - "ClientApplier _insertRows throws on an invalid table name without querying (fail closed)", - "ClientApplier _insertRows upserts attest_validator_stats with ON DUPLICATE KEY UPDATE covering every carried column", - "ClientApplier _insertRows upserts markets with ON DUPLICATE KEY UPDATE covering every carried column", - "ClientApplier _insertRows uses INSERT IGNORE for append-only merkle_epochs", - "ClientApplier _insertRows uses INSERT IGNORE for index tables", - "ClientApplier _insertRows uses INSERT IGNORE for the re-deliverable rollcall_absences", - "ClientApplier _insertRows uses INSERT IGNORE for the re-deliverable rollcalls", - "ClientApplier _insertRows uses INSERT for non-index tables", - "ClientApplier _rebuildBalances error handling rethrows a non-1146 error on rebuildBalances", - "ClientApplier _rebuildBalances error handling swallows a 1146 (table-missing) error on rebuildBalances", - "ClientApplier applyBlock accepts a live block payload with a matching schema_version", - "ClientApplier applyBlock accepts a live block payload without schema_version (pre-5250 server)", - "ClientApplier applyBlock applies block in a transaction", - "ClientApplier applyBlock applies the genesis block (block_index 0) instead of silently dropping it", - "ClientApplier applyBlock does NOT rebuild balances on a decoder replica", - "ClientApplier applyBlock does not issue the reconcile delete mirror when the block carries no reconcile-log rows", - "ClientApplier applyBlock mirrors the anchor-reward winner collapse from this block's reconcile-log pre-images (keyed delete, after inserts, in-txn)", - "ClientApplier applyBlock never opens a transaction when the duplicate guard read faults", - "ClientApplier applyBlock reads the duplicate guard fail-CLOSED (opts.rethrow)", - "ClientApplier applyBlock rebuilds balances when an indexer payload touches credits/debits", - "ClientApplier applyBlock rejects a live block payload with a mismatched schema_version", - "ClientApplier applyBlock rolls back on error", - "ClientApplier applyBlock skips empty table arrays", - "ClientApplier applyBlock skips existing block (duplicate detection)", - "ClientApplier applyBlock skips null payload", - "ClientApplier applyBlock skips payload without block_index", - "ClientApplier applyBlock skips payload without data", - "ClientApplier applyDispensersReplace clears the table even when the new set is empty (decoder)", - "ClientApplier applyDispensersReplace is a no-op on a non-decoder DB", - "ClientApplier applyDispensersReplace replaces atomically: DELETE then INSERT inside one transaction (decoder)", - "ClientApplier applyDispensersReplace rolls back and rethrows if a write fails (decoder, table left intact)", - "ClientApplier applyFullSnapshot aborts the bootstrap (no commit) when local table enumeration fails with a non-schema-gap error", - "ClientApplier applyFullSnapshot binds the scoped state_tree_roots clear to the TICKER, not the full coin name @regression", - "ClientApplier applyFullSnapshot clears a source-empty local table absent from the payload (re-bootstrap staleness)", - "ClientApplier applyFullSnapshot clears tables in reverse order and inserts in forward order", - "ClientApplier applyFullSnapshot does NOT clear replica-local control tables sync_halt / sync_state on full-snapshot apply @regression", - "ClientApplier applyFullSnapshot fails closed on an invalid table name (rejects rather than silently dropping its rows)", - "ClientApplier applyFullSnapshot ignores node-local tables (mempool_transactions) shipped by an older source", - "ClientApplier applyFullSnapshot rolls back on error", - "ClientApplier applyFullSnapshot scoped-clears state_tree_roots at/above the snapshot height before seeding @regression", - "ClientApplier applyFullSnapshot skips null snapshot", - "ClientApplier applyFullSnapshot skips snapshot without tables", - "ClientApplier applyFullSnapshot throws on a schema-version mismatch before opening a transaction", - "ClientApplier applyFullSnapshot tolerates a genuine schema-gap error (1146) on local table enumeration", - "ClientApplier applyIncrementalSnapshot inserts rows without truncation", - "ClientApplier applyIncrementalSnapshot mirrors the anchor-reward winner collapses the catch-up window carried (reconcile-log rows at/above since_block)", - "ClientApplier applyIncrementalSnapshot rebuilds balances when the catch-up touches credits/debits", - "ClientApplier applyIncrementalSnapshot rolls back on error", - "ClientApplier applyIncrementalSnapshot skips a snapshot without tables", - "ClientApplier applyIncrementalSnapshot skips null snapshot", - "ClientApplier applyIncrementalSnapshot throws on a schema-version mismatch", - "ClientApplier scoped balance rebuilds falls back to the FULL rebuild when a row is missing its ids", - "ClientApplier scoped balance rebuilds falls back to the FULL rebuild when the touched-id set exceeds the IN-list cap", - "ClientApplier scoped balance rebuilds passes the distinct touched (address_id, tick_id) ids to rebuildBalances", - "ClientApplier scoped balance rebuilds scopes the incremental catch-up rebuild the same way", - "ClientApplier scoped balance rebuilds skips the rebuild entirely when the touched tables are empty arrays", - "ClientApplier: anchor_actions bundle sections inserts every section of a bundle, naming section_index in the write", - "ClientApplier: anchor_actions bundle sections leaves anchor_actions on a plain INSERT, so a section collision cannot pass silently" + "09f74f1da00d6cad": [ + "validation validateWsEvent accepts block event with block_index 0", + "validation validateWsEvent accepts status event with null block_height", + "validation validateWsEvent accepts status event without block_height", + "validation validateWsEvent accepts valid block event", + "validation validateWsEvent accepts valid reorg event", + "validation validateWsEvent accepts valid status event with block_height", + "validation validateWsEvent rejects array event", + "validation validateWsEvent rejects block event with Infinity block_index", + "validation validateWsEvent rejects block event with NaN block_index", + "validation validateWsEvent rejects block event with missing block_index", + "validation validateWsEvent rejects block event with negative block_index", + "validation validateWsEvent rejects block event with non-numeric block_index", + "validation validateWsEvent rejects missing type field", + "validation validateWsEvent rejects null event", + "validation validateWsEvent rejects reorg event with missing block_index", + "validation validateWsEvent rejects status event with non-numeric block_height", + "validation validateWsEvent rejects string event", + "validation validateWsEvent rejects undefined event", + "validation validateWsEvent rejects unknown event type" + ], + "0a0b1c0489a3d846": [ + "consensus gate registry has exactly the manifest row count", + "consensus gate registry keeps the SHARED block data-only", + "consensus gate registry stores frozen rows but gives each shim a mutable copy", + "consensus gate registry throws a RegistryMissError that names the missing key", + "consensus gate registry throws on a duplicate key" + ], + "0a214ec4ff4e8d5c": [ + "Tier 2 - HubClient @tier2 getIndexerConfigs always returns an array", + "Tier 2 - HubClient @tier2 getIndexerConfigs each returned entry has correct shape", + "Tier 2 - HubClient @tier2 getIndexerConfigs handles completely broken response data structure", + "Tier 2 - HubClient @tier2 getIndexerConfigs handles network errors gracefully", + "Tier 2 - HubClient @tier2 getIndexerConfigs never throws for any hub response shape", + "Tier 2 - HubClient @tier2 getIndexerConfigs skips entries with empty coin keys", + "Tier 2 - HubClient @tier2 parsePort falls back to secondary when primary is empty/null/undefined", + "Tier 2 - HubClient @tier2 parsePort never throws and always returns a non-negative integer", + "Tier 2 - HubClient @tier2 parsePort returns 3306 as fallback for non-parseable inputs", + "Tier 2 - HubClient @tier2 parsePort returns 3306 for negative values", + "Tier 2 - HubClient @tier2 parsePort returns the parsed primary even as string", + "Tier 2 - HubClient @tier2 parsePort returns the parsed primary when valid" + ], + "0a9f32b553d98066": [ + "E2E: Decoder DB Lifecycle Incremental snapshot catches replica up from a since-block, including tx-scoped tables" + ], + "0bdf5df327f12392": [ + "SyncService startup readiness (isReady) gates GET /health on readiness before the per-chain loop", + "SyncService startup readiness (isReady) is not ready before start()", + "SyncService startup readiness (isReady) is ready after start() completes with a legitimately empty chain set", + "SyncService startup readiness (isReady) is still not ready while start() waits on the hub" + ], + "0c06733c3bf59e5e": [ + "ClientSync: indexer head-fork re-delivery decoder head-fork behaviour is unchanged (block_hash mismatch still triggers catch-up) @regression", + "ClientSync: indexer head-fork re-delivery indexer: at-tip re-delivery with IDENTICAL hashes is a silent skip (true duplicate) @regression", + "ClientSync: indexer head-fork re-delivery indexer: at-tip re-delivery with a DIFFERENT hash triggers catch-up (lost 1-block reorg) @regression" ], "0c488b6b47a588af": [ "MerkleTree @consensus @regression buildTree() a single leaf is its own root", @@ -214,22 +260,33 @@ "MerkleTree @consensus @regression generateProof() / verifyProof() round-trip rejects a proof with a tampered sibling hash", "MerkleTree @consensus @regression generateProof() / verifyProof() round-trip verifyProof returns false on missing arguments" ], - "0db309d4b8251770": [ - "Boundary: Source Array Parsing _bootstrapFromSnapshot failure propagation retries with backoff, then succeeds on a later round", - "Boundary: Source Array Parsing _bootstrapFromSnapshot failure propagation throws (does not silently return) when all sources are exhausted", - "Boundary: Source Array Parsing _bootstrapFromSnapshot failure propagation throws when no sources are configured", - "Boundary: Source Array Parsing _bootstrapRotateSources rotation (one round, returns boolean) does not recurse when only 1 source", - "Boundary: Source Array Parsing _bootstrapRotateSources rotation (one round, returns boolean) no sources configured: returns false", - "Boundary: Source Array Parsing _bootstrapRotateSources rotation (one round, returns boolean) rotates sources on failure with 2 sources", - "Boundary: Source Array Parsing _bootstrapRotateSources rotation (one round, returns boolean) stops after exhausting all sources (no infinite recursion)", - "Boundary: Source Array Parsing constructor source parsing empty string \u2192 empty array", - "Boundary: Source Array Parsing constructor source parsing leading comma \u2192 filtered out", - "Boundary: Source Array Parsing constructor source parsing multiple commas \u2192 all empty strings filtered", - "Boundary: Source Array Parsing constructor source parsing only whitespace \u2192 empty array", - "Boundary: Source Array Parsing constructor source parsing single URL \u2192 1-element array", - "Boundary: Source Array Parsing constructor source parsing trailing comma \u2192 filtered out", - "Boundary: Source Array Parsing constructor source parsing two URLs \u2192 2-element array", - "Boundary: Source Array Parsing constructor source parsing whitespace trimmed" + "0d29ac0800550c53": [ + "E2E: Decoder DB Lifecycle Reorg / rollback rolls back blocks + tx-scoped rows and keeps index tables intact" + ], + "0ddb81e3688155bc": [ + "ClientSync.shouldReconcileDispensers (decoder resume cadence) does not force a reconcile on the first cycle when bootstrap already reconciled", + "ClientSync.shouldReconcileDispensers (decoder resume cadence) reconciles every Nth catch-up in steady state", + "ClientSync.shouldReconcileDispensers (decoder resume cadence) reconciles on the first cycle after a resume that skipped bootstrap", + "ClientSync.shouldReconcileDispensers (decoder resume cadence) reconciles when the last reconcile is older than the max interval", + "ClientSync.shouldReconcileDispensers (decoder resume cadence) skips reconcile within the interval and off the periodic cycle", + "ClientSync.shouldReconcileDispensers (decoder resume cadence) treats a max interval of 0 as disabling the time trigger" + ], + "1038be37b3b01cb3": [ + "ClientSync handleReorg calls rollback with the event block_index", + "ClientSync handleReorg handles rollback error gracefully", + "ClientSync handleReorg loads new lastHashes from DB", + "ClientSync handleReorg null tip: ignores the reorg entirely (no rollback, no cursor advance)", + "ClientSync handleReorg resets lastAppliedBlock to block_index - 1", + "ClientSync handleReorg sets lastHashes to null when rolling back to block 0" + ], + "1050d45e360d00f4": [ + "ClientApplier applyFullSnapshot binds the scoped state_tree_roots clear to the TICKER, not the full coin name @regression", + "ClientApplier applyFullSnapshot does NOT clear replica-local control tables sync_halt / sync_state on full-snapshot apply @regression", + "ClientApplier applyFullSnapshot scoped-clears state_tree_roots at/above the snapshot height before seeding @regression" + ], + "131ce9ddc181014a": [ + "SyncService mode branching in start calls startClientMode for client mode", + "SyncService mode branching in start calls startServerMode for server mode" ], "1331c4cc0e5fd805": [ "client-mode sync_meta retention getTransparencyLog passes readOnly and the window instead of dropping them", @@ -241,118 +298,141 @@ "sync_meta count parity while the client window is armed excludes sync_meta from the shortfall check only while the window is armed", "sync_meta count parity while the client window is armed is armed only for a writable client with a positive window" ], - "16a6b835bcc569c7": [ - "M-17: state-commitment input reads fail closed outside a transaction CONTROL: plain doQuery still swallows the same failure and answers []", - "M-17: state-commitment input reads fail closed outside a transaction _applyStakeWeightCap throws on its own read, past the getStatusId hop", - "M-17: state-commitment input reads fail closed outside a transaction getBlockLeafRows throws rather than hashing a truncated leaf set", - "M-17: state-commitment input reads fail closed outside a transaction getStateRootsRow throws rather than reporting \"no prior root\" on a DB fault", - "M-17: state-commitment input reads fail closed outside a transaction getStatusId keeps the fail-soft default for its operational callers", - "M-17: state-commitment input reads fail closed outside a transaction the stake readers throw rather than committing an empty stakes_root" + "1410e3f1c5abfb95": [ + "Tier 1 - ClientApplier @tier1 applyBlock never throws for any payload shape", + "Tier 1 - ClientApplier @tier1 applyBlock transaction is always committed or rolled back, never leaked", + "Tier 1 - ClientApplier @tier1 applyBlock when block already exists, no transaction is opened", + "Tier 1 - ClientApplier @tier1 applyFullSnapshot clears tables in reverse order via DELETE (FK-safe)", + "Tier 1 - ClientApplier @tier1 applyFullSnapshot never throws for any snapshot shape", + "Tier 1 - ClientApplier @tier1 applyIncrementalSnapshot never calls truncateTable", + "Tier 1 - ClientApplier @tier1 applyIncrementalSnapshot never throws for any snapshot shape", + "Tier 1 - ClientApplier @tier1 insertRows batches inserts in groups of 100", + "Tier 1 - ClientApplier @tier1 insertRows does nothing for empty or null rows", + "Tier 1 - ClientApplier @tier1 insertRows never throws for any table name and row array", + "Tier 1 - ClientApplier @tier1 insertRows null and undefined column values become null in query args", + "Tier 1 - ClientApplier @tier1 insertRows uses INSERT IGNORE for all index tables", + "Tier 1 - ClientApplier @tier1 insertRows uses plain INSERT for non-index tables" ], - "1b01123efc4dff07": [ - "assembleStateRoot: reserved-slot carrier is inert @regression explicitly EMPTY reserved sub-roots are byte-identical to the two-argument form", - "assembleStateRoot: reserved-slot carrier is inert @regression ignores keys that are not reserved slot names", - "assembleStateRoot: reserved-slot carrier is inert @regression null / undefined / empty extraSubRoots are byte-identical to the two-argument form", - "assembleStateRoot: reserved-slot carrier is inert @regression still matches merkle.stateRoot for the two v1 sub-roots", - "assembleStateRoot: reserved-slot carrier is inert @regression the ARMED chain commits a DIFFERENT root, which is the whole point of arming", - "assembleStateRoot: reserved-slot carrier is inert @regression the gated block-path value is null on every INERT chain, so its root is the v1 root", - "assembleStateRoot: reserved-slot carrier is real @regression a populated reserved sub-root changes state_root", - "assembleStateRoot: reserved-slot carrier is real @regression an EMPTY reserved slot still proves as EMPTY_SMT_ROOT against the v1 root", - "assembleStateRoot: reserved-slot carrier is real @regression assembleStateRoot agrees with merkle.stateRoot when slots are populated", - "assembleStateRoot: reserved-slot carrier is real @regression each reserved slot occupies its own leaf position", - "assembleStateRoot: reserved-slot carrier is real @regression stateRootProof verifies a reserved sub-root against the assembled root", - "state_root reserved sub-trees: gate is inert EXCEPT the armed set @regression MAINNET IS UNARMED for every slot, at every height (the launch guard)", - "state_root reserved sub-trees: gate is inert EXCEPT the armed set @regression all three testnet chains arm contract_state_root from GENESIS", - "state_root reserved sub-trees: gate is inert EXCEPT the armed set @regression every populated activation key is coin-qualified (:)", - "state_root reserved sub-trees: gate is inert EXCEPT the armed set @regression exactly the armed set is armed, and nothing else on any chain or height", - "state_root reserved sub-trees: gate is inert EXCEPT the armed set @regression no environment variable can arm a slot", - "state_root reserved sub-trees: gate is inert EXCEPT the armed set @regression stateRootVersion reports 1 everywhere EXCEPT at and above an armed height", - "state_root reserved sub-trees: gate is inert EXCEPT the armed set @regression the activation maps hold EXACTLY the armed set (arming is a code change, not config)", - "state_root reserved sub-trees: gate is inert EXCEPT the armed set @regression the armed height is a real boundary, and is chain-local", - "state_root reserved sub-trees: gate is inert EXCEPT the armed set @regression the escrow locked-balance leaf is off everywhere EXCEPT the armed chain", - "state_root reserved sub-trees: gate is inert EXCEPT the armed set @regression the escrow-leaf SHADOW window is CLOSED everywhere, and ARMED WINS when both maps name a height", - "state_root reserved sub-trees: gateSubRoots @regression a bare-network key arms nothing (coin-qualified keys are the only lookup)", - "state_root reserved sub-trees: gateSubRoots @regression an armed escrow leaf flips the derived version to 2 (leaf-set changes are never version-invisible)", - "state_root reserved sub-trees: gateSubRoots @regression drops every candidate on every INERT chain, returning null", - "state_root reserved sub-trees: gateSubRoots @regression fails closed on a malformed MAP threshold, not just a malformed query height", - "state_root reserved sub-trees: gateSubRoots @regression fails closed on an unparseable height", - "state_root reserved sub-trees: gateSubRoots @regression opens for exactly the armed slot, chain and height once a height is set", - "state_root reserved sub-trees: gateSubRoots @regression passes ONLY the armed slot through on the armed chain", - "state_root reserved sub-trees: gateSubRoots @regression returns null for null / empty candidates", - "state_root reserved sub-trees: gateSubRoots @regression the block paths hand assembleStateRoot only gateSubRoots output (the gate is the only permitted writer)", - "state_root reserved sub-trees: gateSubRoots @regression throws on an unknown slot name rather than dropping it silently", - "state_root reserved sub-trees: slot list @regression RESERVED_SUBTREES is exactly the non-v1 tail of merkle.STATE_SUBTREES, in order", - "state_root reserved sub-trees: slot list @regression the frozen slot list has exactly five names (a sixth would change every historical state_root)", - "state_root reserved sub-trees: slot list @regression there is no escrow sub-root: the locked leaf lives inside balances_root" + "14cea56fa69537cd": [ + "ServerPoller stop sets running to false" ], - "1d2c13f91db9640e": [ - "armedMapFingerprint covers every *_activation.js gate file plus the fixed carriers", - "armedMapFingerprint every activation-map carrier under src/ is in the fingerprint set", - "armedMapFingerprint fingerprint is a stable 64-hex string (memoized per process)", - "armedMapFingerprint per-file hashes are the sha256 of the actual file bytes" - ], - "1fdd9eb5a4de22db": [ - "ServerPoller _buildBlockPayload builds complete payload with correct structure", - "ServerPoller _buildBlockPayload collects both decoder blocks hash ids under the shared *_hash_id rule @regression", - "ServerPoller _buildBlockPayload does not run the generic index pass for the decoder", - "ServerPoller _buildBlockPayload extracts the remaining indexer index tables from referenced _id columns", - "ServerPoller _buildBlockPayload fails closed on a TRANSIENT per-table read error (deadlock 1213) so the block is retried, not broadcast incomplete @regression", - "ServerPoller _buildBlockPayload fails closed on a TRANSIENT updated_rows collection error (deadlock 1213) so the block is retried, not broadcast without updated_rows @regression", - "ServerPoller _buildBlockPayload fetches index_addresses by source_id from transactions", - "ServerPoller _buildBlockPayload fetches index_transactions by referenced IDs", - "ServerPoller _buildBlockPayload includes a sync_meta transparency row in the indexer payload", - "ServerPoller _buildBlockPayload includes block-scoped table rows in data", - "ServerPoller _buildBlockPayload keeps state_hash when the view tip IS the block (steady state) or is unknown", - "ServerPoller _buildBlockPayload merges derived anchor/archive rewards (block_index = earn-block E, derive_block_index = this block) into validator_rewards", - "ServerPoller _buildBlockPayload omits sync_meta from the decoder payload", - "ServerPoller _buildBlockPayload returns null when block hash row is missing", - "ServerPoller _buildBlockPayload ships state_hash NULL for burst-built blocks (viewTip ahead of B)", - "ServerPoller _buildBlockPayload ships state_root NULL for burst blocks but keeps balances/merkle roots (@regression)", - "ServerPoller _buildBlockPayload skips a per-table SCHEMA-GAP read error (errno 1146) and still builds the block @regression", - "ServerPoller _buildBlockPayload streams contract_emissions via getEmissionRowsForBlock, not getActionScopedRows", - "ServerPoller _buildBlockPayload streams the blocks.state_hash_id index_transactions row with the live block @regression", - "ServerPoller _poll detects a net-forward reorg via a changed same-height hash", - "ServerPoller _poll detects reorg and broadcasts reorg event", - "ServerPoller _poll does not attempt a transparency prune on reorg for the decoder (no log)", - "ServerPoller _poll does not flag a net-forward reorg when the same-height hash is unchanged", - "ServerPoller _poll does nothing when currentBlock equals lastPolledBlock", - "ServerPoller _poll initializes lastPolledBlock on first poll", - "ServerPoller _poll limits to 100 blocks per poll", - "ServerPoller _poll processes multiple sequential blocks", - "ServerPoller _poll processes new blocks when currentBlock > lastPolledBlock", - "ServerPoller _poll prunes the source transparency log on reorg (to currentBlock + 1)", - "ServerPoller _poll re-evaluates the replica verdict on idle polls", - "ServerPoller _poll resolves a multi-block net-forward reorg to the true fork in a single poll", - "ServerPoller _poll returns early when no blocks in DB", - "ServerPoller _poll snapshot pinning (H-P2) never streams past the snapshot tip when it sits behind the outer read", - "ServerPoller _poll snapshot pinning (H-P2) pins the forward batch to one read snapshot and threads it through every payload read", - "ServerPoller _poll snapshot pinning (H-P2) releases the snapshot even when payload building throws", - "ServerPoller _poll snapshot pinning (H-P2) streams to the snapshot tip when a block landed between the outer read and the snapshot open", - "ServerPoller _resumeCursor (restart resume) @regression decoder resumes from the source tip (no transparency log)", - "ServerPoller _resumeCursor (restart resume) @regression does not skip blocks advanced during downtime when polling resumes", - "ServerPoller _resumeCursor (restart resume) @regression indexer resume is null on a fresh node (empty sync_meta)", - "ServerPoller _resumeCursor (restart resume) @regression indexer resumes from the transparency-log high-water mark, not the source tip", - "ServerPoller _seedReorgGuardHash (durable reorg-guard seed) @regression decoder (no transparency log) seeds from the live source read", - "ServerPoller _seedReorgGuardHash (durable reorg-guard seed) @regression detects a during-downtime reorg on the first poll after restart", - "ServerPoller _seedReorgGuardHash (durable reorg-guard seed) @regression falls back to the live read for a fresh node (no recorded hash) and null cursor", - "ServerPoller _seedReorgGuardHash (durable reorg-guard seed) @regression indexer seeds from the recorded (pre-reorg) hash, NOT a live source read", - "ServerPoller _updateStatus calls broadcaster.updateStatus with correct shape", - "ServerPoller _updateStatus handles null lastPolledBlock", - "ServerPoller _updateStatus replication freshness fails closed when the read throws", - "ServerPoller _updateStatus replication freshness fails closed when the replication status is unreadable", - "ServerPoller _updateStatus replication freshness reports fresh on a primary (not a replica at all)", - "ServerPoller _updateStatus replication freshness reports fresh on a replica inside the lag ceiling", - "ServerPoller _updateStatus replication freshness reports stale past the lag ceiling", - "ServerPoller _updateStatus replication freshness reports stale when the SQL thread stopped (Seconds_Behind NULL)", - "ServerPoller _updateStatus stamps measured_at on a successful measurement, and publishes nothing on a failed one", - "ServerPoller backfillGaps @regression is a no-op for the decoder (no transparency log)", - "ServerPoller backfillGaps @regression is a no-op when the transparency log reports no gaps", - "ServerPoller backfillGaps @regression replays recordBlock for each missing block and recomputes affected epochs", - "ServerPoller backfillGaps @regression skips a gap whose source block has vanished (reorg) without recording it", - "ServerPoller stop sets running to false", - "ServerPoller table lists has action-scoped tables", - "ServerPoller table lists has block-scoped tables", - "ServerPoller table lists has index tables" + "151ff98884592964": [ + "contract_state_root: strict reads @regression a faulting full build THROWS rather than committing EMPTY over a populated table", + "contract_state_root: strict reads @regression a faulting latest-value read THROWS rather than DELETING the key from the tree" + ], + "1628e91f205184a5": [ + "SyncService getHubConfigAgeSeconds returns null when the hub has never answered", + "SyncService getHubConfigAgeSeconds returns whole seconds since the last successful fetch" + ], + "169ecc74d07da9cf": [ + "ClientSync verifyTableCounts (replica-completeness) at the same height, reports a replica-AHEAD delta on exact-parity tables as reason replica-ahead", + "ClientSync verifyTableCounts (replica-completeness) does not fault the completeness check when the schema heal itself throws", + "ClientSync verifyTableCounts (replica-completeness) flags a table the source has rows in but the follower has zeroed", + "ClientSync verifyTableCounts (replica-completeness) heals the schema when a replicated table is missing locally (errno 1146)", + "ClientSync verifyTableCounts (replica-completeness) replica-ahead is gated on equal heights and on the registry exact-parity class", + "ClientSync verifyTableCounts (replica-completeness) reports a table missing entirely from the follower as a full shortfall", + "ClientSync verifyTableCounts (replica-completeness) returns no mismatches when the follower is complete (local >= source)", + "ClientSync verifyTableCounts (replica-completeness) skips a malicious table name without passing it to getTableCount", + "ClientSync verifyTableCounts (replica-completeness) treats absent/invalid table_counts as nothing to check (older source builds)" + ], + "16b6025bc75d7d05": [ + "SyncService waitForHub timeout exits the process after MAX_HUB_WAIT_MS with no hub" + ], + "19b6bdb857cf7156": [ + "ClientSync syncLookupTablesPaged catch-up: starts from the replica MAX(id) so only NEW rows are fetched", + "ClientSync syncLookupTablesPaged decoder: pages pubkeys by its surrogate id cursor", + "ClientSync syncLookupTablesPaged pages one table by id cursor until has_more=false, applying each non-empty page", + "ClientSync syncLookupTablesPaged stops if has_more is true but the cursor cannot advance (no infinite spin)", + "ClientSync syncLookupTablesPaged throws on a schema-version mismatch (fail closed)" + ], + "1e2917ef8e99fd7f": [ + "contract_state_root: arming boundary and reorg @regression a reorg back below the armed height recommits EMPTY and restores the exact v1 state_root", + "contract_state_root: arming boundary and reorg @regression below the armed height the slot is EMPTY and state_root is byte-identical to v1", + "contract_state_root: arming boundary and reorg @regression the arming block full-builds (its predecessor stored NULL) and moves state_root" + ], + "1f144263f64d3946": [ + "BlockBroadcaster applied-block tracking does not advance _syncLastSentBlock for non-block events", + "BlockBroadcaster applied-block tracking ignores a heartbeat with a non-integer/negative/infinite appliedBlock", + "BlockBroadcaster applied-block tracking ignores malformed or unknown inbound messages", + "BlockBroadcaster applied-block tracking initialises _syncLastSentBlock and _syncAppliedBlock to null", + "BlockBroadcaster applied-block tracking reports heartbeatReceived true even when caught up (lag 0)", + "BlockBroadcaster applied-block tracking reports lag = lastSentBlock - appliedBlock after a heartbeat", + "BlockBroadcaster applied-block tracking reports null appliedBlock and lag for a subscriber with no heartbeat", + "BlockBroadcaster applied-block tracking returns an empty array for an unknown chain/network", + "BlockBroadcaster applied-block tracking updates _syncAppliedBlock when a heartbeat message arrives", + "BlockBroadcaster applied-block tracking updates _syncLastSentBlock to the block height on broadcast" + ], + "1f961d589efa3f2e": [ + "06 Incremental Catch-Up 10-block gap", + "06 Incremental Catch-Up 100-block gap", + "06 Incremental Catch-Up 50-block gap", + "06 Incremental Catch-Up 500-block gap", + "06 Incremental Catch-Up catch-up rate scales linearly" + ], + "202bed8f78d5d96d": [ + "Database.beginReadSnapshot() acquires a DEDICATED connection and runs SET / START TRANSACTION on it", + "Database.beginReadSnapshot() does NOT touch the shared transactionConnection (decoupled from the writer)", + "Database.beginReadSnapshot() on query error: releases the dedicated connection and throws (shared field untouched)", + "Database.commitReadSnapshot() / rollbackReadSnapshot() both are no-ops on a null connection", + "Database.commitReadSnapshot() / rollbackReadSnapshot() commitReadSnapshot commits then releases the connection", + "Database.commitReadSnapshot() / rollbackReadSnapshot() commitReadSnapshot still releases when commit throws", + "Database.commitReadSnapshot() / rollbackReadSnapshot() rollbackReadSnapshot rolls back then releases the connection", + "Database.commitReadSnapshot() / rollbackReadSnapshot() rollbackReadSnapshot swallows a rollback error but still releases (best-effort)", + "Database.commitTransaction() commits, releases, nulls, returns true on success", + "Database.commitTransaction() on commit error: rolls back, releases, nulls, throws", + "Database.commitTransaction() returns false when no active transactionConnection", + "Database.createDatabase() creates the DB and returns true on success", + "Database.createDatabase() retries once on error then succeeds", + "Database.createDatabase() throws for an invalid dbName without connecting", + "Database.verifyDatabase() retries once on error then succeeds", + "Database.verifyDatabase() returns false when DB is not found", + "Database.verifyDatabase() returns true when DB exists", + "Database.verifyDatabaseOnce() ends connection in finally even when query throws", + "Database.verifyDatabaseOnce() returns false when DB not found, still ends connection", + "Database.verifyDatabaseOnce() returns true when DB exists and always ends the connection", + "Database.verifyDatabaseOnce() throws (no retry) when createConnection rejects", + "Database.verifySyncTables() creates table when it does not exist (calls createTableFromFile)", + "Database.verifySyncTables() decoder dbType: creates ONLY sync_halt (transparency log is indexer-only)", + "Database.verifySyncTables() does not create table when it already exists", + "Database.verifySyncTables() skips non-.sql files" + ], + "20341c70321425c4": [ + "ClientSync lookup-hole repair and count-check scoping @regression KEEPS index_transactions strict, because that check is what found the mainnet hole", + "ClientSync lookup-hole repair and count-check scoping @regression a repairing (fromZero) pass asks ClientApplier for the strict IGNORE check", + "ClientSync lookup-hole repair and count-check scoping @regression excludes the events operational log from the count check, whose counts cannot converge", + "ClientSync lookup-hole repair and count-check scoping @regression fromZero pages from id 0, never consulting the high-water mark", + "ClientSync lookup-hole repair and count-check scoping @regression leaves tables not named in fromZero on the ordinary high-water cursor", + "ClientSync lookup-hole repair and count-check scoping @regression the ordinary high-water cursor path never asks for the strict IGNORE check" + ], + "207558fd52fb2bf8": [ + "ClientApplier security applyBlock: data key validation applies data with valid table name", + "ClientApplier security applyBlock: data key validation rejects a block carrying an invalid table name key (fail closed, transaction rolled back)", + "ClientApplier security applyFullSnapshot: table name validation one invalid table poisons the whole snapshot: nothing commits", + "ClientApplier security applyFullSnapshot: table name validation rejects a snapshot carrying a path traversal table name (fail closed)", + "ClientApplier security applyFullSnapshot: table name validation rejects a snapshot carrying an invalid table name (fail closed, transaction rolled back)", + "ClientApplier security applyFullSnapshot: table name validation truncates valid table names", + "ClientApplier security insertRows: column name validation allows valid column names", + "ClientApplier security insertRows: column name validation rejects column name with backtick", + "ClientApplier security insertRows: column name validation rejects column name with semicolon", + "ClientApplier security insertRows: column name validation rejects column name with space", + "ClientApplier security insertRows: column name validation rejects empty column name", + "ClientApplier security insertRows: table name validation allows valid table name", + "ClientApplier security insertRows: table name validation rejects empty table name", + "ClientApplier security insertRows: table name validation rejects table name with SQL comment", + "ClientApplier security insertRows: table name validation rejects table name with backtick", + "ClientApplier security insertRows: table name validation rejects table name with dot notation", + "ClientApplier security insertRows: table name validation rejects table name with path traversal", + "ClientApplier security insertRows: table name validation rejects table name with semicolon", + "ClientApplier security insertRows: table name validation rejects table name with space" + ], + "20ed0b54513008c0": [ + "Integration: SPV sub-tree shadow columns, cross-twin replication timing leaves both shadow maps exactly as it found them", + "Integration: SPV sub-tree shadow columns, cross-twin replication timing the block payload carries both sub-tree tables, which is the whole timing premise", + "Integration: SPV sub-tree shadow columns, cross-twin replication timing the follower computes both shadow values from rows that arrived in the same block", + "Integration: SPV sub-tree shadow columns, cross-twin replication timing withholding the journal rows changes the escrow shadow, so a replication lag is detectable" + ], + "22f878636d1e21f6": [ + "ClientSync security connectWebSocket: maxPayload passes maxPayload to WebSocket constructor" ], "2442df610ebb6911": [ "coin-registry conformance (vendored copy) @regression byte-identity to canonical xchain-hub/src/coins BTC.js is byte-identical to the canonical xchain-hub copy", @@ -375,33 +455,256 @@ "collectMaturedCooldownCredits returns [] when the completed status id is unresolved", "collectMaturedCooldownCredits skips a missing table (errno 1146) rather than throwing" ], + "2696e26e03274736": [ + "HubClient hubConfigRegressed is false for a bare-map payload with no seq/configs wrapper", + "HubClient hubConfigRegressed is false when there is no prior watermark to regress against", + "HubClient hubConfigRegressed is true when seq drops below the last-seen value even if watermark is unchanged", + "HubClient hubConfigRegressed is true when watermark drops below the last-seen value" + ], + "27948aa1cde1b70e": [ + "BlockBroadcaster getValidatorHeartbeats with an expected-validator roster does not duplicate a reporting roster member as absent", + "BlockBroadcaster getValidatorHeartbeats with an expected-validator roster reports a non-roster reporter alongside absent roster members", + "BlockBroadcaster getValidatorHeartbeats with an expected-validator roster reports all roster members absent when none have reported", + "BlockBroadcaster getValidatorHeartbeats with an expected-validator roster surfaces roster members that have never reported as status absent" + ], + "2831ab2c30bba1b2": [ + "Boundary: HubClient Port Parsing getIndexerConfigs integration defaults to 3306 when neither port field present", + "Boundary: HubClient Port Parsing getIndexerConfigs integration falls back to port when db_port absent", + "Boundary: HubClient Port Parsing getIndexerConfigs integration uses db_port from hub config", + "Boundary: HubClient Port Parsing parsePort static method defaults to 3306 for non-numeric primary", + "Boundary: HubClient Port Parsing parsePort static method defaults to 3306 when both are absent", + "Boundary: HubClient Port Parsing parsePort static method defaults to 3306 when both are empty", + "Boundary: HubClient Port Parsing parsePort static method defaults to 3306 when both are null", + "Boundary: HubClient Port Parsing parsePort static method falls back to secondary when primary is empty string", + "Boundary: HubClient Port Parsing parsePort static method falls back to secondary when primary is null", + "Boundary: HubClient Port Parsing parsePort static method falls back to secondary when primary is undefined", + "Boundary: HubClient Port Parsing parsePort static method float string truncated", + "Boundary: HubClient Port Parsing parsePort static method integer 0 preserved", + "Boundary: HubClient Port Parsing parsePort static method integer value (not string) works", + "Boundary: HubClient Port Parsing parsePort static method negative port defaults to 3306", + "Boundary: HubClient Port Parsing parsePort static method uses secondary when primary is non-numeric", + "Boundary: HubClient Port Parsing parsePort static method valid port: returns as-is", + "Boundary: HubClient Port Parsing parsePort static method zero: preserved (not treated as falsy)" + ], "283afce58127f133": [ "ClientSync: snapshot catch-up repairs the tip hash pair @regression does not report a bogus fork when the new tip is re-delivered after a catch-up", "ClientSync: snapshot catch-up repairs the tip hash pair @regression leaves lastHashes describing the new tip, not the pre-catch-up tip", "ClientSync: snapshot catch-up repairs the tip hash pair @regression still reports a REAL fork at the head (the guard is not disarmed)" ], - "324f0246f861a9ae": [ - "Database schema self-heal: one startup completes columns then key rebuilds adds each column BEFORE the rebuild that names it", - "Database schema self-heal: one startup completes columns then key rebuilds converges a follower sitting in the deferred state on its next start", - "Database schema self-heal: one startup completes columns then key rebuilds is idle on the second and third startup", - "Database schema self-heal: one startup completes columns then key rebuilds keeps the stale keys when the column ADD is refused, and says so", - "Database schema self-heal: one startup completes columns then key rebuilds never defers the work to a next startup" + "289986a69cb8db56": [ + "ClientRollback rollback aborts (fail-closed) on a transient error in the contract_emissions delete", + "ClientRollback rollback aborts (fail-closed) on a transient error in the icons orphan-sweep", + "ClientRollback rollback aborts (fail-closed) on a transient error in the merkle_epochs reorg delete", + "ClientRollback rollback aborts (fail-closed) on a transient error in the sync_meta reorg delete", + "ClientRollback rollback aborts the rollback (fail-closed) on a transient error in a generic DELETE loop", + "ClientRollback rollback aborts the rollback on a transient error in the blockTables loop", + "ClientRollback rollback deletes validator_rewards by derive_block_index as well, mirroring the source", + "ClientRollback rollback handles per-table errors gracefully (table may not exist)", + "ClientRollback rollback restores a stamped ATTEST v5 batch head before the action-scoped deletes", + "ClientRollback rollback rolls back transaction on error and rethrows", + "ClientRollback rollback skips the ATTEST batch-head restore when firstActionIndex is null (no orphaned continuation)", + "ClientRollback rollback swallows a schema gap on the ATTEST batch-head restore but aborts on a transient fault", + "ClientRollback rollback swallows missing-table errors on every optional delete + the generic loops" ], - "34ecc125f5c3c276": [ - "state_hash index-map class (id-determinism P4) - follower twin @regression armed: a divergent id->address pair changes state_hash (follower would HALT)", - "state_hash index-map class (id-determinism P4) - follower twin @regression gate: regtest armed from genesis, arms at/after the per-chain height", - "state_hash index-map class (id-determinism P4) - follower twin @regression inert: follower preimage is byte-identical to the pre-feature shape" + "28b5b3553b3a0524": [ + "SyncService startClientMode starts a ClientSync for each discovered database" ], - "364d8f8918f3b7b9": [ - "Boundary: Circuit Breaker backoff delay calculation adds up to 30% jitter", - "Boundary: Circuit Breaker backoff delay calculation uses correct exponential progression", - "Boundary: Circuit Breaker circuit open rejection rejects immediately during cooldown", - "Boundary: Circuit Breaker failure threshold (10) 10 failures: circuit opens and throws", - "Boundary: Circuit Breaker failure threshold (10) 9 failures: circuit stays closed", - "Boundary: Circuit Breaker half-open recovery re-opens on failure during half-open", - "Boundary: Circuit Breaker half-open recovery transitions to half-open after cooldown expires", - "Boundary: Circuit Breaker max retry attempts (30) throws after 30 attempts without reaching circuit threshold", - "Boundary: Circuit Breaker transaction connection bypass returns transactionConnection when set (bypasses pool)" + "2b8574874fbaf660": [ + "Database.addMissingColumns(): edge branches reads COLUMN_NAME (uppercase) from information_schema rows", + "Database.addMissingColumns(): edge branches throws and logs when ALTER TABLE fails", + "Database.getActionScopedRows() queries with action/transaction join", + "Database.getBlockHashRow() PROPAGATES a query error with opts.rethrow (fail-closed duplicate guard)", + "Database.getBlockHashRow() decoder: returns null when no rows", + "Database.getBlockHashRow() decoder: returns row with block_hash only", + "Database.getBlockHashRow() indexer: returns null when no rows", + "Database.getBlockHashRow() indexer: returns row with ledger/actions/contract hashes", + "Database.getBlockHashRow() swallows a query error and returns null by default (fail-soft preserved)", + "Database.getBlockRows() decoder: uses block_hash column", + "Database.getBlockRows() indexer: uses ledger/actions/contract hash columns", + "Database.getBlockScopedRows() leaves every other block-scoped table on block_index", + "Database.getBlockScopedRows() queries the given table by block_index", + "Database.getBlockScopedRows() scopes a close_block-keyed table by close_block, not the class default", + "Database.getFirstActionIndex() PROPAGATES a query error with opts.rethrow (fail-closed rollback gate)", + "Database.getFirstActionIndex() returns Number when found", + "Database.getFirstActionIndex() returns null when no rows", + "Database.getFirstActionIndex() swallows a query error and returns null by default (fail-soft preserved)", + "Database.getNonEmptyActionScopedTables() drops candidates the source schema does not have (one missing table fails the whole UNION)", + "Database.getNonEmptyActionScopedTables() issues no query at all when no candidate exists", + "Database.getNonEmptyActionScopedTables() probes every existing candidate in ONE round-trip, with getActionScopedRows' predicate", + "Database.getNonEmptyActionScopedTables() refuses an unsafe table identifier before it reaches the query string" + ], + "2c00f2c184ea8958": [ + "ClientSync: handleEvent lastKnownServerBlock branches does not update lastKnownServerBlock on block event when incoming <= current", + "ClientSync: handleEvent lastKnownServerBlock branches does not update lastKnownServerBlock on status event when incoming <= current" + ], + "2c414fbb86440ec6": [ + "Integration: WebSocket Broadcasting initial status on connect sends status message when status data exists", + "Integration: WebSocket Broadcasting invalid subscribe path destroys socket for unrecognized path", + "Integration: WebSocket Broadcasting multiple chains only delivers events to matching chain subscribers", + "Integration: WebSocket Broadcasting per-IP connection limit closes connection when limit exceeded", + "Integration: WebSocket Broadcasting subscribe and receive block receives block event after new block is polled", + "Integration: WebSocket Broadcasting subscribe and receive block receives reorg event" + ], + "2d5af37f72b7535a": [ + "M-17: state-commitment input reads fail closed outside a transaction CONTROL: plain doQuery still swallows the same failure and answers []", + "M-17: state-commitment input reads fail closed outside a transaction applyStakeWeightCap throws on its own read, past the getStatusId hop", + "M-17: state-commitment input reads fail closed outside a transaction getBlockLeafRows throws rather than hashing a truncated leaf set", + "M-17: state-commitment input reads fail closed outside a transaction getStateRootsRow throws rather than reporting \"no prior root\" on a DB fault", + "M-17: state-commitment input reads fail closed outside a transaction getStatusId keeps the fail-soft default for its operational callers", + "M-17: state-commitment input reads fail closed outside a transaction the stake readers throw rather than committing an empty stakes_root" + ], + "2dcdcb24f7d411bb": [ + "validation extractColumnDefinition does not match a constraint identifier as a column", + "validation extractColumnDefinition handles enum definitions with embedded commas and quotes", + "validation extractColumnDefinition preserves commas inside the type definition", + "validation extractColumnDefinition rejects a bare comma smuggling ADD COLUMN", + "validation extractColumnDefinition rejects a bare comma smuggling RENAME COLUMN", + "validation extractColumnDefinition rejects a line carrying a smuggled second statement", + "validation extractColumnDefinition rejects a multi-action ALTER smuggled via a bare comma (DROP COLUMN)", + "validation extractColumnDefinition returns null for a column that is not present", + "validation extractColumnDefinition returns null for non-string input", + "validation extractColumnDefinition returns the backtick-quoted name plus definition, comma stripped", + "validation extractColumnDefinition still accepts a precision type whose only commas are inside parens" + ], + "2de09f9ac8510fc7": [ + "ClientSync: bulk-range boundary recompute fails CLOSED @regression HALTS (boundary-read-error) when the committed hash READ fails on every retry @regression", + "ClientSync: bulk-range boundary recompute fails CLOSED @regression HALTS (local-recompute-divergence) on a boundary hash mismatch", + "ClientSync: bulk-range boundary recompute fails CLOSED @regression HALTS (recompute-error) when the recompute errors on every retry", + "ClientSync: bulk-range boundary recompute fails CLOSED @regression does NOT halt when a transient READ error clears within the retries @regression", + "ClientSync: bulk-range boundary recompute fails CLOSED @regression does NOT halt when a transient error clears within the retries", + "ClientSync: bulk-range boundary recompute fails CLOSED @regression reads the committed boundary hash FAIL-CLOSED (rethrow), not on the fail-soft default @regression", + "ClientSync: bulk-range boundary recompute fails CLOSED @regression skips (no halt) when the committed boundary hash is not yet resolvable", + "ClientSync: bulk-range boundary recompute fails CLOSED @regression the LIVE path still fails open: a persistent error does not throw without failClosed" + ], + "2de415b648901dff": [ + "ClientSync: heartbeat flushHeartbeat returns early when lastAppliedBlock is null", + "ClientSync: heartbeat flushHeartbeat sends WS message to OPEN connections and clears timer", + "ClientSync: heartbeat scheduleHeartbeat arms a 5s timer when delta < 10 and no timer running", + "ClientSync: heartbeat scheduleHeartbeat flushes immediately when >= 10 blocks advanced", + "ClientSync: heartbeat scheduleHeartbeat flushes immediately when _hbLastSentBlock is null", + "ClientSync: heartbeat sendRestHeartbeat does NOT send the inbound SYNC_API_KEY upstream", + "ClientSync: heartbeat sendRestHeartbeat omits Authorization header when no upstream key", + "ClientSync: heartbeat sendRestHeartbeat posts to correct URL with Bearer header when the upstream key is set", + "ClientSync: heartbeat upstreamHeaders carries the upstream key to snapshot reads, not just heartbeats" + ], + "2f20c354797e7735": [ + "SnapshotBuilder streamTableRowsById clamps an oversized limit to the ceiling", + "SnapshotBuilder streamTableRowsById decoder: pages the pubkeys table by its surrogate monotonic id cursor", + "SnapshotBuilder streamTableRowsById queries id > after_id ORDER BY id LIMIT, and sets has_more when a full page returns", + "SnapshotBuilder streamTableRowsById rejects a non-pageable table with 400", + "SnapshotBuilder streamTableRowsById streams an id-ordered page with max_id and has_more=false when short" + ], + "3005f26e0e504c49": [ + "01 Payload Throughput dense blocks (200 actions/block)", + "01 Payload Throughput heavy blocks (50 actions/block)", + "01 Payload Throughput light blocks (1 action/block)", + "01 Payload Throughput medium blocks (10 actions/block)" + ], + "3107b91431c55ba5": [ + "ServerPoller backfillGaps @regression is a no-op for the decoder (no transparency log)", + "ServerPoller backfillGaps @regression is a no-op when the transparency log reports no gaps", + "ServerPoller backfillGaps @regression replays recordBlock for each missing block and recomputes affected epochs", + "ServerPoller backfillGaps @regression skips a gap whose source block has vanished (reorg) without recording it" + ], + "313ce50c8014b176": [ + "E2E: Large Data Volume 6.1 Bootstrap with 500 blocks bootstraps large dataset within timeout", + "E2E: Large Data Volume 6.2 Incremental catch-up of 200 blocks catches up large delta within timeout", + "E2E: Large Data Volume 6.3 Single block with many actions syncs a block with 1000 actions", + "E2E: Large Data Volume 6.4 Sustained throughput keeps up with 1 block per 200ms for 100 blocks", + "E2E: Large Data Volume 6.5 Snapshot download for large dataset serves gzip-compressed snapshot for 200 blocks" + ], + "316993ccc3fd07eb": [ + "armed map v2: manifest completeness over src/ every row resolves to the registry value, with no refusal", + "armed map v2: manifest completeness over src/ keys are unique and every one is in the key grammar", + "armed map v2: manifest completeness over src/ sync has no ProtocolChanges table, so it owes no protocol_changes.changes rows", + "armed map v2: manifest completeness over src/ the registry and manifest carry exactly the expected keys", + "armed map v2: manifest completeness over src/ the shim keys equal the independent expected-key census", + "armed map v2: manifest completeness over src/ the shim scan finds all twelve gate files and all 39 rows" + ], + "319ef1f0f909fe9d": [ + "Chaos: source cursor read fails closed a genuinely empty source is still a quiet no-op, not an error", + "Chaos: source cursor read fails closed a source-DB outage surfaces out of poll instead of reading as an idle chain", + "Chaos: source cursor read fails closed an outage on a poller with no cursor yet does not seed lastPolledBlock from a swallowed error" + ], + "324f0246f861a9ae": [ + "Database schema self-heal: one startup completes columns then key rebuilds adds each column BEFORE the rebuild that names it", + "Database schema self-heal: one startup completes columns then key rebuilds converges a follower sitting in the deferred state on its next start", + "Database schema self-heal: one startup completes columns then key rebuilds is idle on the second and third startup", + "Database schema self-heal: one startup completes columns then key rebuilds keeps the stale keys when the column ADD is refused, and says so", + "Database schema self-heal: one startup completes columns then key rebuilds never defers the work to a next startup" + ], + "347de06fd7b53919": [ + "Advisory table-content parity computeTableContentChecksums a failed table listing degrades to probing, not to an empty result", + "Advisory table-content parity computeTableContentChecksums a source publishes its id ceiling and a follower reuses it verbatim", + "Advisory table-content parity computeTableContentChecksums an invalid or absent window falls back to the default rather than disabling the check", + "Advisory table-content parity computeTableContentChecksums case 7: one unreadable table does not sink the other tables' check", + "Advisory table-content parity computeTableContentChecksums publishes the window, the block and a sparse per-table map", + "Advisory table-content parity computeTableContentChecksums reads the decoder plan on a decoder handle (no actions table to join)", + "Advisory table-content parity computeTableContentChecksums skips tables the local schema does not have (an older replica must not spam or fail)", + "Advisory table-content parity computeTableContentChecksums windows blocks as [upto - window + 1, upto] and never below zero" + ], + "3498ab5bdacfbd7d": [ + "contract_state_root: frozen row-to-leaf mapping @regression the SQL shape is pinned at source: binary collation, no pre-max NULL filter", + "contract_state_root: incremental equals full build @regression a block that deletes the last live key returns the tree to EMPTY", + "contract_state_root: incremental equals full build @regression a block touching nothing leaves the root unchanged", + "contract_state_root: incremental equals full build @regression no prior root full-builds instead of threading from EMPTY (the silent-fork refusal)", + "contract_state_root: incremental equals full build @regression threading block by block lands on the same root as one full build", + "contract_state_root: key derivation @regression a 0x00-bearing state_key still throws, and that is the known surface", + "contract_state_root: key derivation @regression contract_index type does not change the key (driver bigint config is not consensus)", + "contract_state_root: key derivation @regression is domain-separated from the balance and escrow key domains", + "contract_state_root: key derivation @regression separates chain, network, contract and key (no field can be smeared into another)" + ], + "34ecc125f5c3c276": [ + "state_hash index-map class (id-determinism P4) - follower twin @regression armed: a divergent id->address pair changes state_hash (follower would HALT)", + "state_hash index-map class (id-determinism P4) - follower twin @regression gate: regtest armed from genesis, arms at/after the per-chain height", + "state_hash index-map class (id-determinism P4) - follower twin @regression inert: follower preimage is byte-identical to the pre-feature shape" + ], + "350a60ae36012e8e": [ + "Smoke: Client Mode ClientApplier applies a block without error", + "Smoke: Client Mode full bootstrap populates replica", + "Smoke: Client Mode replica DB connection succeeds", + "Smoke: Client Mode replica has indexer tables", + "Smoke: Client Mode snapshot is downloadable and parseable", + "Smoke: Client Mode sync_meta table exists in replica" + ], + "35f586531a7008e6": [ + "Database.beginTransaction() acquires a connection and calls beginTransaction on it", + "Database.beginTransaction() if transactionConnection already exists: releases it first, then opens new one", + "Database.beginTransaction() releases conn and nulls transactionConnection when beginTransaction throws", + "Database.doQuery() coerces plain-object args to string, leaves Buffer intact", + "Database.doQuery() does NOT release conn when inside a transaction", + "Database.doQuery() explicit conn arg: query errors propagate (caller rolls back the snapshot)", + "Database.doQuery() explicit conn arg: runs on that connection, never acquires/releases one", + "Database.doQuery() on query error in non-tx path with opts.rethrow: logs, releases, AND re-throws (fail-closed)", + "Database.doQuery() on query error in non-tx path: logs error, does NOT throw, returns []", + "Database.doQuery() on query error inside a transaction: logs AND re-throws", + "Database.doQuery() returns [] and does NOT call getConnection when query is null", + "Database.doQuery() returns [] when query is undefined", + "Database.doQuery() runs a query via a connection and releases it (non-tx path)", + "Database.getConnection(): circuit breaker circuit open + cooldown expired \u2192 transitions to half-open, succeeds", + "Database.getConnection(): circuit breaker circuit open + cooldown not expired \u2192 throws immediately", + "Database.getConnection(): circuit breaker half-open \u2192 success \u2192 closes circuit", + "Database.getConnection(): circuit breaker happy path: returns connection and resets failures", + "Database.getConnection(): circuit breaker maxAttempts exhaustion: throws when failures < threshold", + "Database.getConnection(): circuit breaker retry-with-backoff: fails once then succeeds", + "Database.getConnection(): circuit breaker returns transactionConnection directly when one is active", + "Database.getConnection(): circuit breaker threshold exceeded: circuit opens and throws", + "Database.releaseConnection() is a no-op when transactionConnection is null", + "Database.releaseConnection() releases and nulls transactionConnection when present", + "Database.rollbackTransaction() is a no-op when no active transaction", + "Database.rollbackTransaction() releases in finally even when rollback throws", + "Database.rollbackTransaction() rolls back and releases when transactionConnection is active" + ], + "364d8f8918f3b7b9": [ + "Boundary: Circuit Breaker backoff delay calculation adds up to 30% jitter", + "Boundary: Circuit Breaker backoff delay calculation uses correct exponential progression", + "Boundary: Circuit Breaker circuit open rejection rejects immediately during cooldown", + "Boundary: Circuit Breaker failure threshold (10) 10 failures: circuit opens and throws", + "Boundary: Circuit Breaker failure threshold (10) 9 failures: circuit stays closed", + "Boundary: Circuit Breaker half-open recovery re-opens on failure during half-open", + "Boundary: Circuit Breaker half-open recovery transitions to half-open after cooldown expires", + "Boundary: Circuit Breaker max retry attempts (30) throws after 30 attempts without reaching circuit threshold", + "Boundary: Circuit Breaker transaction connection bypass returns transactionConnection when set (bypasses pool)" ], "37100c93c95b19e0": [ "HubClient hub-vs-bundle consensus-hash cross-check does not re-log an unchanged mismatch on the next poll", @@ -413,12 +716,70 @@ "HubClient hub-vs-bundle consensus-hash cross-check says nothing when every served hash matches the bundle", "HubClient hub-vs-bundle consensus-hash cross-check says nothing when the hub predates the field" ], - "3b2f993a46d5c309": [ - "ClientSync._fetchAndApplySchema multi-pass + fail-closed halt aborts the bootstrap round once a schema halt is recorded", - "ClientSync._fetchAndApplySchema multi-pass + fail-closed halt does NOT halt on a schema-fetch transport failure (not a DDL fault)", - "ClientSync._fetchAndApplySchema multi-pass + fail-closed halt records a durable halt when a genuine DDL fault survives the fixpoint", - "ClientSync._fetchAndApplySchema multi-pass + fail-closed halt records a durable halt when the column self-heal on an existing table is refused", - "ClientSync._fetchAndApplySchema multi-pass + fail-closed halt resolves FK ordering across passes without halting" + "3771857a17674d3d": [ + "ClientSync: small branches applyBlockEvent sets lastHashes to {block_hash} for decoder dbType", + "ClientSync: small branches applyBlockEvent: state-commitment roots withheld at an active height HALTS when only block_merkle_root is withheld (a correct balances_root is not a pass)", + "ClientSync: small branches applyBlockEvent: state-commitment roots withheld at an active height HALTS with state-commitment-missing when the source omits balances_root", + "ClientSync: small branches applyBlockEvent: state-commitment roots withheld at an active height a state-hash read failure then redelivery still compares the commitment roots", + "ClientSync: small branches applyBlockEvent: state-commitment roots withheld at an active height clears the carried roots once every gate passes, so a later duplicate stays a skip", + "ClientSync: small branches applyBlockEvent: state-commitment roots withheld at an active height does NOT halt on a null state_root: ServerPoller nulls it for catch-up-burst blocks", + "ClientSync: small branches applyBlockEvent: state-commitment roots withheld at an active height does NOT halt when the replica itself says the commitment is not active", + "ClientSync: small branches applyBlockEvent: state-commitment roots withheld at an active height still halts with state-commitment-divergence on a root MISMATCH", + "ClientSync: small branches handleBlock (decoder): logs gap and triggers catch-up when blockIndex > lastApplied+1", + "ClientSync: small branches handleBlock: HALT_ON_DIVERGENCE=true calls haltOnDivergence on hash mismatch", + "ClientSync: small branches handleBlock: STRICT mode rejects on timeout and records the strict block (M-22)", + "ClientSync: small branches handleReorg: a legitimate below-tip reorg still rolls back and moves the cursor", + "ClientSync: small branches handleReorg: decoder track also HALTS on max-depth exceed", + "ClientSync: small branches handleReorg: exceeds MAX_ROLLBACK_DEPTH \u2192 HALTS and does NOT rollback", + "ClientSync: small branches handleReorg: target ABOVE the tip is ignored (no rollback, no cursor advance)" + ], + "3787112c2730702b": [ + "Advisory table-content parity content digest a single altered amount diverges (the smallest possible tamper)", + "Advisory table-content parity content digest case 2: a faithful replica reproduces the source digest", + "Advisory table-content parity content digest case 3: equal row count + substituted content diverges (row counts miss this)", + "Advisory table-content parity content digest case 4: row order is not content (unlike the consensus hashes)", + "Advisory table-content parity content digest case 5: the stripped blocks.id surrogate is excluded, so it cannot false-alarm", + "Advisory table-content parity content digest column ORDER and driver value typing do not change the digest", + "Advisory table-content parity content digest the digest is table-scoped: identical rows under different table names differ", + "Advisory table-content parity content digest the generated contract_state.state_key_bin column is excluded", + "Advisory table-content parity content digest the node-local contract_emissions.id column is excluded, so it cannot false-alarm", + "Advisory table-content parity content digest the node-local sync_meta.id/logged_at columns are excluded, so they cannot false-alarm" + ], + "37bc72a0a6979a91": [ + "Integration: contract_emissions reorg-safe streaming (emissions fix) @regression getEmissionRowsForBlock includes NULL-action_index (SLASH) emissions the action-scoped path drops" + ], + "39c89678ecd7b9af": [ + "Advisory table-content parity compareTableContent a table present on one side only is skipped with its own reason", + "Advisory table-content parity compareTableContent case 2: identical maps match", + "Advisory table-content parity compareTableContent case 3: equal count + different digest is the reported mismatch", + "Advisory table-content parity compareTableContent case 6: a row-count difference is skipped, never reported as divergence", + "Advisory table-content parity compareTableContent compares numeric counts across the JSON round-trip (string n must not read as a difference)", + "Advisory table-content parity compareTableContent tolerates a missing or empty payload on either side" + ], + "3b26854153f9cf95": [ + "/status missing_tables is an empty array on a complete replica", + "/status missing_tables is null, not [], when the table listing fails", + "/status missing_tables is published in server mode too (a source missing a table it should stream)", + "/status missing_tables names the missing tables on a replica that otherwise looks perfectly healthy", + "/status missing_tables scopes to the decoder replicated set on a decoder replica", + "ClientSync.warnMissingTables exposes the list via getMissingTables()", + "ClientSync.warnMissingTables is advisory: a listing failure never throws, and leaves the list unknown (null)", + "ClientSync.warnMissingTables reports null before the check has run", + "ClientSync.warnMissingTables runs during start(), before the replica enters live-follow", + "ClientSync.warnMissingTables stays silent when the schema is complete", + "ClientSync.warnMissingTables warns ONCE naming every missing table", + "missingReplicatedTables ignores extra local tables (only source-side coverage matters)", + "missingReplicatedTables names every replicated table the schema lacks, sorted", + "missingReplicatedTables returns an empty array when the schema carries every replicated table", + "missingReplicatedTables returns null (unknown), never [], when the table listing is unavailable", + "missingReplicatedTables scopes to the dbType (decoder set, not indexer set)" + ], + "3c190d07814f2bdb": [ + "Integration: REST API GET /transparency/:dbType/:chain/:network/root/latest returns 400 for decoder dbType", + "Integration: REST API GET /transparency/:dbType/:chain/:network/root/latest returns 403 in client mode", + "Integration: REST API GET /transparency/:dbType/:chain/:network/root/latest returns 404 for unknown chain/network", + "Integration: REST API GET /transparency/:dbType/:chain/:network/root/latest returns latest Merkle root after an epoch is committed", + "Integration: REST API GET /transparency/:dbType/:chain/:network/root/latest returns null epoch and merkle_root when log is empty" ], "3c56690bfa37c105": [ "Boundary: Block Index Values block_index = 0 continuity check: 0 \u2192 1 is valid", @@ -431,6 +792,30 @@ "Boundary: Block Index Values large block indices beyond safe integer: precision loss documented", "Boundary: Block Index Values reorg boundary at block 1 reorg from 10 to 0: reorg event at block_index 1" ], + "3db5faf2fec0a01f": [ + "BlockBroadcaster evictStaleValidators hard-removes a non-roster entry that stays stale past a second TTL window", + "BlockBroadcaster evictStaleValidators keeps a roster member visible as stale indefinitely", + "BlockBroadcaster evictStaleValidators leaves a fresh entry untouched", + "BlockBroadcaster evictStaleValidators restores a stale validator to known/unknown on the next heartbeat", + "BlockBroadcaster evictStaleValidators transitions an entry past the TTL to stale instead of deleting it" + ], + "3e452242329a55a6": [ + "Database constructor: dbType default defaults dbType to \"indexer\" when not provided", + "Database.close() calls pool.end() and resolves", + "Database.close() swallows a pool.end() error" + ], + "3f4b732becaa031e": [ + "Advisory table-content parity coverage contract bounds match the scope each table actually replicates through", + "Advisory table-content parity coverage contract every replicated decoder table is either covered or declared excluded", + "Advisory table-content parity coverage contract every replicated indexer table is either covered or declared excluded", + "Advisory table-content parity coverage contract the block-bounded read excludes NULL-block rows, as the index-map checksum does", + "Advisory table-content parity coverage contract the indexer dispensers table is covered even though the decoder one is carved out", + "Advisory table-content parity coverage contract the operator carve-outs are exactly markets (indexer) and dispensers (decoder)", + "Advisory table-content parity coverage contract the second exclusion class is exactly the state_hash (in-place mutated) tables" + ], + "3f757b2a543b0143": [ + "SnapshotBuilder streamIncrementalSnapshot snapshot-replication tables full-dumps indexer pubkeys instead of action-scoping it into errno 1054" + ], "40158d38b88066f8": [ "sqlUtil splitSqlStatements does not split on a semicolon inside a comment", "sqlUtil splitSqlStatements drops empty statements produced by trailing/duplicate semicolons", @@ -450,41 +835,12 @@ "sqlUtil stripSqlLineComments removes a trailing -- line comment, leaving a newline", "sqlUtil stripSqlLineComments returns empty string for empty input" ], - "409fbf440d108d07": [ - "/status missing_tables is an empty array on a complete replica", - "/status missing_tables is null, not [], when the table listing fails", - "/status missing_tables is published in server mode too (a source missing a table it should stream)", - "/status missing_tables names the missing tables on a replica that otherwise looks perfectly healthy", - "/status missing_tables scopes to the decoder replicated set on a decoder replica", - "ClientSync._warnMissingTables exposes the list via getMissingTables()", - "ClientSync._warnMissingTables is advisory: a listing failure never throws, and leaves the list unknown (null)", - "ClientSync._warnMissingTables reports null before the check has run", - "ClientSync._warnMissingTables runs during start(), before the replica enters live-follow", - "ClientSync._warnMissingTables stays silent when the schema is complete", - "ClientSync._warnMissingTables warns ONCE naming every missing table", - "missingReplicatedTables ignores extra local tables (only source-side coverage matters)", - "missingReplicatedTables names every replicated table the schema lacks, sorted", - "missingReplicatedTables returns an empty array when the schema carries every replicated table", - "missingReplicatedTables returns null (unknown), never [], when the table listing is unavailable", - "missingReplicatedTables scopes to the dbType (decoder set, not indexer set)" - ], - "41839f13ef76cf66": [ - "ClientApplier in-place updated-rows apply _maybeRederiveEscrow runs the escrow re-derive only when an escrow-relevant table is present", - "ClientApplier in-place updated-rows apply _upsertRows emits INSERT ... ON DUPLICATE KEY UPDATE writing every column", - "ClientApplier in-place updated-rows apply _upsertRows throws on an invalid table identifier without querying (fail closed)", - "ClientApplier in-place updated-rows apply applyBlock UPSERTs payload.updated_rows for surviving rows", - "updatedRows.collectUpdatedRows carries a DELEGATE v1 signing-key rotation on surviving stake AND cooldown rows", - "updatedRows.collectUpdatedRows carries the stamped ATTEST v5 batch head on the block its completing v6 chunk landed in", - "updatedRows.collectUpdatedRows dedups a row reached by two classes (deactivated AND slashed) by action_index", - "updatedRows.collectUpdatedRows detects SLASH amount cuts via the debit log join and v0 request_status flips", - "updatedRows.collectUpdatedRows detects deactivation stamps by value-threshold [from+delay, to+delay]", - "updatedRows.collectUpdatedRows emits the v0 request flip and the v5 batch head as separate attests rows, deduped by action_index", - "updatedRows.collectUpdatedRows keys the VOTE poll class on resolved_block OR a fired deferred-callback due block (one scan)", - "updatedRows.collectUpdatedRows refreshes surviving tokens rows for ticks touched by ledger changes in the window", - "updatedRows.collectUpdatedRows rethrows a non-schema error from the attest batch-head class (never a silent drop)", - "updatedRows.collectUpdatedRows skips the attest batch-head class on a pre-batch-rail schema instead of throwing", - "updatedRows.collectUpdatedRows skips the deactivation_block class entirely when activationDelay is null", - "updatedRows.collectUpdatedRows uses target_table to separate contract_stakes vs contract_unstakes" + "4149fd390fa625eb": [ + "Database.ensureReplicaSecondaryIndexes(): validator_rewards reward_unique qualifier key adds round_qualifier itself and then rebuilds the key in the same pass", + "Database.ensureReplicaSecondaryIndexes(): validator_rewards reward_unique qualifier key does nothing when reward_unique is absent", + "Database.ensureReplicaSecondaryIndexes(): validator_rewards reward_unique qualifier key is a no-op for a decoder replica (indexer-only)", + "Database.ensureReplicaSecondaryIndexes(): validator_rewards reward_unique qualifier key leaves an unexpected reward_unique definition alone", + "Database.ensureReplicaSecondaryIndexes(): validator_rewards reward_unique qualifier key leaves the stale key alone when the column ADD is refused" ], "436350992c034c95": [ "Utility getDataHash handles BigInt fields", @@ -545,6 +901,105 @@ "coverage ratchet floors fails the job on a shortfall rather than only reporting it", "coverage ratchet floors ships the coverage:check script the CI coverage job invokes" ], + "447987fa6855b9be": [ + "ClientSync handleEvent detects gap on status event and triggers catch-up", + "ClientSync handleEvent does not trigger catch-up when lastAppliedBlock is null", + "ClientSync handleEvent does not trigger catch-up when no gap", + "ClientSync handleEvent routes block events to handleBlock", + "ClientSync handleEvent routes reorg events to handleReorg", + "ClientSync handleEvent runs the completeness sweep against the source that sent the status tick @regression", + "ClientSync handleEvent upstream replication evidence is unknown, not fresh, before any status event", + "ClientSync handleEvent upstream replication evidence keeps the source height, staleness verdict and lag from a status event", + "ClientSync handleEvent upstream replication evidence re-reads the verdict on a status tick that does not advance the height", + "ClientSync handleEvent upstream replication evidence reads a server older than the fields as unknown rather than fresh", + "ClientSync handleEvent upstream replication evidence takes the worst verdict across sources and ignores an evicted one" + ], + "4504591b9086da2b": [ + "Rollback coverage guard @regression ATTEST v5 batch-head status restore is mirrored across xchain-indexer and xchain-sync (bespoke-logic drift guard)", + "Rollback coverage guard @regression COINPay match-status re-derive SQL is identical across xchain-indexer and xchain-sync (cross-repo drift guard)", + "Rollback coverage guard @regression F-1: tokens is not in any updatedRows mutation-class array (supply rides the ledger-driven pass + token_supply hash class)", + "Rollback coverage guard @regression F-2: buildStateHashData includes cooldown-maturity refund credit in credits class (maturity fixture)", + "Rollback coverage guard @regression F-2: buildStateHashData includes the anchor CRC-failure parent in the anchor_invalid preimage class (value fixture)", + "Rollback coverage guard @regression F-2: collectUpdatedRows returns the invalid_archive-stamped anchor parent by value (CRC-failure fixture)", + "Rollback coverage guard @regression F-5: OPERATOR_LOCAL_TABLES equals the registry-derived exclusion set plus the three permitted non-registry names", + "Rollback coverage guard @regression F-5: hub-mirrored tables are absent from the ServerPoller replicated universe (snapshot-exclusion contract)", + "Rollback coverage guard @regression ServerPoller streams index_addresses via the generic *_id pass (non-tx-interned completeness) @regression", + "Rollback coverage guard @regression VOTE polls re-open reset is mirrored across xchain-indexer and xchain-sync (bespoke-logic drift guard)", + "Rollback coverage guard @regression _cappedStakeWeightsSql is identical across xchain-indexer and xchain-sync (cross-repo drift guard)", + "Rollback coverage guard @regression _stakeWeightsSql is identical across xchain-indexer and xchain-sync (cross-repo drift guard)", + "Rollback coverage guard @regression anchor invalid_archive to unverified reset is mirrored across xchain-indexer and xchain-sync (bespoke-logic drift guard)", + "Rollback coverage guard @regression archive-head version set is [1] via the shared stateHash constant, consumed by updatedRows", + "Rollback coverage guard @regression archive_rollback_author_scope_gate.js is byte-identical across xchain-indexer and xchain-sync", + "Rollback coverage guard @regression attests is rolled back on the replica under its consolidated name, not the phantom split names", + "Rollback coverage guard @regression balances is recomputed, not blindly deleted by index", + "Rollback coverage guard @regression contract slash-restore SQL is identical across xchain-indexer and xchain-sync (cross-repo drift guard)", + "Rollback coverage guard @regression contractStateSubtree.test.js is byte-identical across xchain-sync and xchain-indexer, modulo sibling require depth (cross-repo twin)", + "Rollback coverage guard @regression contract_state_subtree.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression cooldown-maturity reversal is mirrored across xchain-indexer and xchain-sync (bespoke-logic drift guard)", + "Rollback coverage guard @regression cross-chain mirror reorg delete SQL is identical across xchain-indexer and xchain-sync (cross-repo drift guard)", + "Rollback coverage guard @regression db/subtree/node_store_rows.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression db/subtree/orphan_stats_reads.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression delegations deactivation reset is the threshold form on both sides (bespoke-logic drift guard)", + "Rollback coverage guard @regression demands a known network, because the publisher scope is armed", + "Rollback coverage guard @regression escrow re-derive SQL is identical across xchain-indexer and xchain-sync (cross-repo drift guard)", + "Rollback coverage guard @regression escrowLeafSubtree.test.js is byte-identical across xchain-sync and xchain-indexer, modulo sibling require depth (cross-repo twin)", + "Rollback coverage guard @regression escrow_leaf_subtree.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression every replicated DECODER table is handled on reorg", + "Rollback coverage guard @regression every replicated INDEXER table is handled on reorg", + "Rollback coverage guard @regression every table the source indexer rolls back is mirrored by ClientRollback (cross-repo drift guard)", + "Rollback coverage guard @regression every utf8mb4 widen entry is carried by a dated xchain-indexer migration (source/replica lockstep)", + "Rollback coverage guard @regression forward cooldown-credit selection mirrors the reverse delete keys (bespoke-logic drift guard)", + "Rollback coverage guard @regression forward derived-reward selection mirrors the derive_block_index rollback key, and the reconcile DELETE is mirrored (bespoke-logic drift guard)", + "Rollback coverage guard @regression forward recovery-reward selection mirrors the rollback key (bespoke-logic drift guard)", + "Rollback coverage guard @regression index id lookups are rolled back on the replica and mirror the source indexer (^id consensus)", + "Rollback coverage guard @regression merkle.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression pair-scoped IDX-2 markets deletion is mirrored across xchain-indexer and xchain-sync (parity drift guard)", + "Rollback coverage guard @regression prices is rolled back on the replica (regression: this was the drift that motivated the guard)", + "Rollback coverage guard @regression publisher-scope heights are the 2026-09-09 ruling values", + "Rollback coverage guard @regression registry replica-flagged orphan sweeps are mirrored across xchain-indexer and xchain-sync (parity drift guard)", + "Rollback coverage guard @regression sanity: ServerPoller declares a meaningful indexer table set", + "Rollback coverage guard @regression stake_weight_collation_gate.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression stateHash.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression stateSubtreeActivation.test.js is byte-identical across xchain-sync and xchain-indexer, modulo sibling require depth (cross-repo twin)", + "Rollback coverage guard @regression state_commitment_gate.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression state_hash.js selection predicates mirror the replicated mutation classes", + "Rollback coverage guard @regression state_subtree_gate.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression state_subtree_gate.js is byte-identical in xchain-explorer too (escrow-leaf liveness refusal)", + "Rollback coverage guard @regression state_subtree_gate.js is byte-identical in xchain-sdk too (client liveness export)", + "Rollback coverage guard @regression stream:special bucket tables join the reorg-coverage universe", + "Rollback coverage guard @regression swq_source_cap_gate.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression table_lifecycle.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression table_lifecycle/action_tables.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression table_lifecycle/block_and_special_tables.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression the replica calls the COINPay re-derive, and never on a truncated replica", + "Rollback coverage guard @regression updated_rows carries the BET status flips keyed by their stamp columns", + "Rollback coverage guard @regression updated_rows carries the DELEGATE v1 rotation rewrite keyed by the rotations journal window", + "Rollback coverage guard @regression updated_rows carries the VOTE poll finalization flip keyed by resolved_block", + "Rollback coverage guard @regression updated_rows carries the cooldown-maturity status_id flip keyed by cooldown_end_block", + "Rollback coverage guard @regression utf8mb4Columns.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)" + ], + "45fff32ccaa4f955": [ + "BlockBroadcaster getStatus freshness expiry broadcastStatus publishes the expired verdict, not the cached healthy one", + "BlockBroadcaster getStatus freshness expiry does not mutate the cached object, so a recovered poll is not poisoned", + "BlockBroadcaster getStatus freshness expiry expires the freshness verdict of a status measured before the poller stopped", + "BlockBroadcaster getStatus freshness expiry leaves an UNDATED status alone rather than demoting on a guess", + "BlockBroadcaster getStatus freshness expiry returns a freshly measured status unchanged" + ], + "4647d4059a28745e": [ + "ClientApplier applyIncrementalSnapshot inserts rows without truncation", + "ClientApplier applyIncrementalSnapshot mirrors the anchor-reward winner collapses the catch-up window carried (reconcile-log rows at/above since_block)", + "ClientApplier applyIncrementalSnapshot rebuilds balances when the catch-up touches credits/debits", + "ClientApplier applyIncrementalSnapshot rolls back on error", + "ClientApplier applyIncrementalSnapshot skips a snapshot without tables", + "ClientApplier applyIncrementalSnapshot skips null snapshot", + "ClientApplier applyIncrementalSnapshot throws on a schema-version mismatch" + ], + "48914b893fa0ef67": [ + "ServerPoller resumeCursor (restart resume) @regression decoder resumes from the source tip (no transparency log)", + "ServerPoller resumeCursor (restart resume) @regression does not skip blocks advanced during downtime when polling resumes", + "ServerPoller resumeCursor (restart resume) @regression indexer resume is null on a fresh node (empty sync_meta)", + "ServerPoller resumeCursor (restart resume) @regression indexer resumes from the transparency-log high-water mark, not the source tip" + ], "48d7bc42ba69d0ed": [ "Boundary: Config Parsing NaN inputs default gracefully BLOCK_POLL_INTERVAL=undefined defaults to 3000", "Boundary: Config Parsing NaN inputs default gracefully HUB_PORT=\"\" defaults to 10000", @@ -577,6 +1032,30 @@ "Boundary: Config Parsing zero values (falsy-zero) preserves SNAPSHOT_RATE_INCR=0", "Boundary: Config Parsing zero values (falsy-zero) preserves SYNC_API_PORT=0" ], + "48fecddfd5831993": [ + "E2E: Disconnect/Resume Parity 10.4 Divergence halt enforcement halts durably on recompute divergence; live AND catch-up refuse to advance; clearHalt resumes" + ], + "4938e9a593e806aa": [ + "SyncService discoverChains SYNC_EXCLUDE drops a listed chain before any DB pool / ClientSync is created", + "SyncService discoverChains client mode (source reachable): replicates schema, verifies tables, starts a ClientSync", + "SyncService discoverChains client mode (source unreachable): falls through to server /schema fetch; still verifies sync tables for decoder", + "SyncService discoverChains client mode REFUSES a bootstrap-depth key naming no discovered chain, before starting any sync", + "SyncService discoverChains client mode REFUSES a malformed checkpoint pin override, before starting any sync", + "SyncService discoverChains client mode accepts a bootstrap-depth key whose chain the hub published under its full name", + "SyncService discoverChains client mode accepts a well-formed checkpoint pin override", + "SyncService discoverChains server mode ignores bootstrap-depth keys entirely (the var governs nothing there)", + "SyncService discoverChains server mode with REPLICA_DB_HOST re-serves from the local replica", + "SyncService discoverChains server mode without REPLICA_DB_HOST connects to the hub-provided coordinates", + "SyncService discoverChains skips already-known chains" + ], + "4ad4873eb9337e0e": [ + "E2E: Proxy-trust client attribution HTTP snapshot budgets with TRUST_PROXY off keys every forwarded caller on the socket address", + "E2E: Proxy-trust client attribution HTTP snapshot budgets with TRUST_PROXY on charges the forwarded client rather than the proxy socket address", + "E2E: Proxy-trust client attribution HTTP snapshot budgets with TRUST_PROXY on does not let one client exhaust another client budget", + "E2E: Proxy-trust client attribution HTTP snapshot budgets with TRUST_PROXY on ignores entries beyond the one trusted hop, so a forged prefix buys no budget", + "E2E: Proxy-trust client attribution WebSocket per-IP cap collapses every subscriber onto the socket address when TRUST_PROXY is off", + "E2E: Proxy-trust client attribution WebSocket per-IP cap gives each forwarded client its own connection allowance when TRUST_PROXY is on" + ], "4bbfbfece133da72": [ "train_activation TRAIN_ACTIVATION (the shipped map) names every row as a bare X.Y.Z version, so nothing in it is unorderable", "train_activation TRAIN_ACTIVATION (the shipped map) pins the launch floor at zero on every network", @@ -603,6 +1082,24 @@ "train_activation resolveRuleSet returns null when the clock is unusable or the network is unnamed", "train_activation resolveRuleSet returns the greatest entry at or below the height on that network" ], + "4c7a6b9fa31958b9": [ + "SnapshotBuilder branch coverage getOrderedTables drops operator-local tables and tolerates the uppercase TABLE_NAME variant", + "SnapshotBuilder branch coverage streamFullSnapshot aborts the whole snapshot on a per-table read error rather than omitting the table", + "SnapshotBuilder branch coverage streamFullSnapshot rolls back and rethrows when the snapshot read throws", + "SnapshotBuilder branch coverage streamFullSnapshot skips zero-count tables without failing the snapshot", + "SnapshotBuilder branch coverage streamFullSnapshot still returns quietly on a client-disconnect abort (not treated as a read error)", + "SnapshotBuilder branch coverage streamFullSnapshot writes empty hash headers when the hashRow lacks fields, comma-joins tables/rows, and serializes BigInt", + "SnapshotBuilder branch coverage streamIncrementalSnapshot decoder: emits X-Block-Hash and scopes skip/block/tx/full-dump tables correctly", + "SnapshotBuilder branch coverage streamIncrementalSnapshot fails closed (rejects + rolls back) on a transient per-table read error during incremental @regression", + "SnapshotBuilder branch coverage streamIncrementalSnapshot fails closed on a connection-drop (no errno) per-table read error during incremental @regression", + "SnapshotBuilder branch coverage streamIncrementalSnapshot indexer: emits empty hash headers, dumps full + action-scoped tables, and comma-joins them", + "SnapshotBuilder branch coverage streamIncrementalSnapshot indexer: scopes contract_emissions by block through the execution_index chain, not the action_index cursor @regression", + "SnapshotBuilder branch coverage streamIncrementalSnapshot indexer: skips middle tables when there is no firstActionIndex (no actions since the cursor)", + "SnapshotBuilder branch coverage streamIncrementalSnapshot indexer: still ships internal emissions when firstActionIndex is null @regression", + "SnapshotBuilder branch coverage streamIncrementalSnapshot rolls back and rethrows when the incremental read throws before streaming", + "SnapshotBuilder branch coverage streamIncrementalSnapshot ships matured cooldown refund credits when firstActionIndex is null (quiet window) @regression", + "SnapshotBuilder branch coverage streamIncrementalSnapshot swallows a per-table SCHEMA-GAP read error (errno 1146) during incremental" + ], "4d1ce9c4b6023937": [ "ClientSync: multi-source Byzantine quorum @regression 3-source majority applies applies the block once 2 of 3 sources agree, without waiting for the 3rd", "ClientSync: multi-source Byzantine quorum @regression 3-source majority applies strikes the dissenting minority source when the majority applies", @@ -629,104 +1126,123 @@ "ClientSync: multi-source Byzantine quorum @regression no-source-quorum halt log-only mode (HALT_ON_DIVERGENCE=false) refuses to apply but does not halt", "ClientSync: multi-source Byzantine quorum @regression strike sliding window prunes strikes older than SOURCE_STRIKE_WINDOW so stale strikes do not evict" ], - "503d2c2e161e195c": [ - "state_key_collation_activation fails closed (off) on an unknown chain or malformed height", - "state_key_collation_activation is armed from genesis on regtest", - "state_key_collation_activation resolves the : key ahead of a bare network key", - "state_key_collation_activation uses per-coin thresholds (LTC and DOGE differ from BTC)" - ], - "532c53b5adb93aa6": [ - "HubClient _call multi-endpoint fallback falls back to the next endpoint and stickies the good one", - "HubClient _call multi-endpoint fallback returns null and records failures when every endpoint fails", - "HubClient _hubConfigRegressed is false for a bare-map payload with no seq/configs wrapper", - "HubClient _hubConfigRegressed is false when there is no prior watermark to regress against", - "HubClient _hubConfigRegressed is true when seq drops below the last-seen value even if watermark is unchanged", - "HubClient _hubConfigRegressed is true when watermark drops below the last-seen value", - "HubClient _parsePort defaults to 3306 for a non-numeric or negative value", - "HubClient _parsePort defaults to 3306 when both are absent", - "HubClient _parsePort parses a numeric primary", - "HubClient _parsePort preserves a literal 0 (does not fall through to default)", - "HubClient _parsePort uses the fallback when primary is absent/empty", - "HubClient constructor builds the correct URL", - "HubClient constructor: array form defaults a non-numeric port to 10000", - "HubClient constructor: array form honors https via the legacy port arg", - "HubClient constructor: array form uses an explicit endpoint array verbatim", - "HubClient credential tier asks for secrets on the initial fetch", - "HubClient credential tier falls back to the bulk key when the hub does not split the tier", - "HubClient credential tier keeps asking on the delta poll, cursor and all", - "HubClient credential tier names the cause once when the hub redacts anyway, not once per poll", - "HubClient credential tier says nothing when the hub served the credentials", - "HubClient credential tier sends HUB_CONFIG_SECRETS_API_KEY when the hub splits the credential tier", - "HubClient getDecoderConfigs extracts xchain-decoder entries", - "HubClient getDecoderConfigs skips non-object coin/network values defensively", - "HubClient getIndexerConfigs defaults db_host to 127.0.0.1 when neither present", - "HubClient getIndexerConfigs extracts xchain-indexer entries", - "HubClient getIndexerConfigs falls back db_host to host", - "HubClient getIndexerConfigs handles multiple chains", - "HubClient getIndexerConfigs returns empty array when hub returns null", - "HubClient getIndexerConfigs skips empty coin keys", - "HubClient getIndexerConfigs skips networks without xchain-indexer module", - "HubClient getallconfigs cursor + watermark handling merges a delta against the cursor it previously sent", - "HubClient getallconfigs cursor + watermark handling records lastSuccessfulFetchAt on a successful bare-map fetch and resets the cursor", - "HubClient getallconfigs cursor + watermark handling resets the cursor and re-fetches full when it fails over to a different endpoint", - "HubClient getallconfigs cursor + watermark handling treats a watermarked payload as a full tree on the first fetch (no cursor sent yet)", - "HubClient getallconfigs cursor + watermark handling unwraps a { configs, seq } payload (no watermark) and resets the cursor", - "HubClient getallconfigs returns null on error", - "HubClient getallconfigs returns null when no result in response", - "HubClient getallconfigs returns parsed result on success", - "HubClient getallconfigs watermark regression discards the cache and re-fetches full when the same endpoint serves a lower watermark", - "HubClient getallconfigs watermark regression does not treat a regressed-but-unwrapped (no seq/configs) payload as a regression", + "4d60233a4d0d52f7": [ + "Integration: REST API GET /status returns null values when no blocks", + "Integration: REST API GET /status returns status for all chains" + ], + "4ee867ce8010316d": [ + "ClientSync decoder bootstrap completeness bootstrapFromSnapshot wiring does not run the decoder check in single-source mode", + "ClientSync decoder bootstrap completeness bootstrapFromSnapshot wiring runs the decoder completeness check even when VERIFY_HASHES is false", + "ClientSync decoder bootstrap completeness bootstrapFromSnapshot wiring takes the indexer hash path (not the decoder check) for indexer dbType", + "ClientSync decoder bootstrap completeness verifyDecoderCompleteness flags a truncated snapshot loudly when the source has more rows", + "ClientSync decoder bootstrap completeness verifyDecoderCompleteness is a no-op for non-decoder dbType", + "ClientSync decoder bootstrap completeness verifyDecoderCompleteness passes quietly when the follower is complete" + ], + "4f4e462e9354e761": [ + "ClientSync security fetchAndApplySchema: DDL validation accepts valid CREATE TABLE DDL", + "ClientSync security fetchAndApplySchema: DDL validation continues processing when one table is invalid", + "ClientSync security fetchAndApplySchema: DDL validation does not splice a bare-comma multi-action ALTER on schema catch-up", + "ClientSync security fetchAndApplySchema: DDL validation rejects DDL containing CREATE TRIGGER", + "ClientSync security fetchAndApplySchema: DDL validation rejects DDL that starts with DROP TABLE", + "ClientSync security fetchAndApplySchema: DDL validation rejects invalid table name with special chars" + ], + "50469ad456b170f3": [ + "E2E: API Correctness 9.1 Status endpoint reflects live state returns current block height after new blocks", + "E2E: API Correctness 9.2 Schema endpoint returns complete DDL returns CREATE TABLE statements for all tables", + "E2E: API Correctness 9.3 WebSocket observer receives blocks receives block events in order", + "E2E: API Correctness 9.4 WebSocket observer receives reorg receives reorg event when blocks are removed", + "E2E: API Correctness 9.5 Status endpoint with no data returns null block_height when DB is empty", + "E2E: API Correctness 9.6 Incremental snapshot endpoint returns only data since the given block", + "E2E: API Correctness 9.7 Unknown chain returns 404 returns 404 for unknown chain/network" + ], + "50994261d736f8b5": [ + "ClientSync security handleBlock: strict cross-source timeout HASH_CONFIRM_STRICT=false applies block on timeout", + "ClientSync security handleBlock: strict cross-source timeout HASH_CONFIRM_STRICT=true rejects block on timeout" + ], + "51383bd614fcbfae": [ + "E2E: Disconnect/Resume Parity 10.6 Connection flapping repeated disconnect/reconnect cycles end byte-identical" + ], + "517ad59201348d3a": [ + "Tier 1 - HashVerifier @tier1 compareBlockHashes always returns { match: boolean, blockHeight, mismatches: array }", + "Tier 1 - HashVerifier @tier1 compareBlockHashes each mismatch entry has { field, a, b }", + "Tier 1 - HashVerifier @tier1 compareBlockHashes match is true iff mismatches is empty", + "Tier 1 - HashVerifier @tier1 compareBlockHashes mismatch fields are always from the known set", + "Tier 1 - HashVerifier @tier1 compareBlockHashes mismatches length is always 0\u20133", + "Tier 1 - HashVerifier @tier1 compareBlockHashes never throws for any inputs", + "Tier 1 - HashVerifier @tier1 compareBlockHashes same object reference always matches", + "Tier 1 - HashVerifier @tier1 verifyChainContinuity always returns { valid: boolean, reason: string|null }", + "Tier 1 - HashVerifier @tier1 verifyChainContinuity never throws for any inputs", + "Tier 1 - HashVerifier @tier1 verifyChainContinuity valid is false when there is a block gap", + "Tier 1 - HashVerifier @tier1 verifyChainContinuity valid is true for exactly sequential blocks", + "Tier 1 - HashVerifier @tier1 verifyChainContinuity valid is true when prevBlockIndex is null" + ], + "5229b20ad602f73b": [ + "Integration: token supply recompute is idempotent: a second recompute leaves every supply unchanged", + "Integration: token supply recompute recomputes each token supply byte-identically to (credits - debits) + escrows" + ], + "52c69be5fa7605f0": [ + "Integration: REST API GET /transparency/:dbType/:chain/:network/roots returns paginated transparency log" + ], + "52fd8b56df0fa3ee": [ "HubClient parseEndpoints defaults host/port/proto when nothing is configured", "HubClient parseEndpoints falls back to HUB_API_HOST/HUB_PORT when no validators are set", "HubClient parseEndpoints parses a comma-separated HUB_VALIDATORS list, prefixing bare hosts", "HubClient parseEndpoints prefixes bare HUB_VALIDATORS hosts with https when configured", - "HubClient parseEndpoints uses https in the fallback path when HUB_PROTOCOL is https", - "HubClient ping returns false on error", - "HubClient ping returns falsy when result is null", - "HubClient ping returns true on successful response", - "HubClient ping sends correct JSON-RPC payload" + "HubClient parseEndpoints uses https in the fallback path when HUB_PROTOCOL is https" + ], + "53f2c023f224ee8b": [ + "ClientRollback rollback aborts before the transaction when the first-action read faults", + "ClientRollback rollback aborts before the transaction when the market-pair read faults", + "ClientRollback rollback deletes contract_emissions first", + "ClientRollback rollback deletes from action-scoped tables with action_index", + "ClientRollback rollback deletes from block-scoped tables with block_index", + "ClientRollback rollback deletes from merkle_epochs by end_block, mirroring the server pruneFrom (item 4770)", + "ClientRollback rollback deletes from sync_meta", + "ClientRollback rollback gets first action index for the block", + "ClientRollback rollback prunes the hub-mirrored per-action tables scoped to this chain and firstActionIndex", + "ClientRollback rollback reads the affected market pairs fail-CLOSED (opts.rethrow)", + "ClientRollback rollback reads the first action index fail-CLOSED (opts.rethrow)", + "ClientRollback rollback recalculates balances from credits/debits", + "ClientRollback rollback skips action-scoped deletes when firstActionIndex is null", + "ClientRollback rollback still deletes the cross_chain mirrors when bridge_transfers is missing (errno 1146)", + "ClientRollback rollback still skips the market sweep on a schema gap (errno 1146)", + "ClientRollback rollback wraps everything in a transaction" + ], + "549430c7ecacfc94": [ + "ClientSync bootstrapFromHeight VERIFY_RECOMPUTE: recomputes the terminal block and HALTS on mismatch", + "ClientSync bootstrapFromHeight clamps base to 0 when depth exceeds the tip", + "ClientSync bootstrapFromHeight re-pages lookups AFTER applying the block window (closes the T1_ into an uppercased CHAIN:NETWORK map", + "config SYNC_BOOTSTRAP_DEPTH records every raw env key it saw, whatever the value", + "config SYNC_BOOTSTRAP_DEPTH resolves the documented DOGE_TESTNET key to the key ClientSync looks up", + "config SYNC_EXCLUDE defaults to an empty array", + "config SYNC_EXCLUDE drops empty segments", + "config SYNC_EXCLUDE parses, trims, and deduplicates a comma list", + "config SYNC_META_RETENTION_BLOCKS defaults to 0 (retention disabled) when unset", + "config SYNC_META_RETENTION_BLOCKS is 0 for a non-numeric, empty or negative value", + "config SYNC_META_RETENTION_BLOCKS reads a positive window", + "config SYNC_MODE passthrough passes through the env value", + "config VERIFY_HASHES boolean returns false when set to \"FALSE\" (case-insensitive)", + "config VERIFY_HASHES boolean returns false when set to \"False\"", + "config VERIFY_HASHES boolean returns false when set to \"false\"", + "config VERIFY_HASHES boolean returns true for any value other than \"false\"", + "config VERIFY_HASHES boolean returns true when not set", + "config VERIFY_HASHES boolean returns true when set to \"true\"", + "config assertBootstrapDepthChains REFUSES a depth-0 key naming no discovered chain (0 is the full-snapshot branch)", + "config assertBootstrapDepthChains REFUSES a key whose chain was never discovered", + "config assertBootstrapDepthChains REFUSES a key whose network was never discovered", + "config assertBootstrapDepthChains REFUSES a malformed key with no CHAIN_NETWORK split", + "config assertBootstrapDepthChains REFUSES an unknown coin rather than defaulting it to depth 0", + "config assertBootstrapDepthChains accepts a config with no depth keys at all", + "config assertBootstrapDepthChains accepts a key naming a discovered chain (full-name spelling)", + "config assertBootstrapDepthChains accepts a key naming a discovered chain (ticker spelling)", + "config defaults returns correct defaults when no env vars set", + "config hardcoded values does not expose the retired WS_BACKPRESSURE_LIMIT", + "config hardcoded values includes CLIENT_RECONNECT_DELAY", + "config hardcoded values includes HASH_CONFIRM_TIMEOUT", + "config hardcoded values includes HUB_REPOLL_INTERVAL", + "config hardcoded values includes WS_BACKPRESSURE_MAX_BYTES default", + "config hardcoded values includes WS_BACKPRESSURE_STALL_MS default", + "config hardcoded values includes WS_PING_INTERVAL", + "config hardcoded values includes WS_STATUS_INTERVAL", + "config numeric coercion falls back to default for non-numeric SYNC_API_PORT", + "config numeric coercion parses BLOCK_POLL_INTERVAL as integer", + "config numeric coercion parses HUB_PORT as integer", + "config numeric coercion parses SYNC_API_PORT as integer", + "config readEnvNow reads the current value on every call: set, read, change, read again, unset", + "config string passthrough passes HUB_API_HOST", + "config string passthrough passes REPLICA_DB_HOST" + ], + "5b17637c84d5cb70": [ + "Integration: REST API GET /transparency/:dbType/:chain/:network/proof/:block_index returns 400 for decoder dbType", + "Integration: REST API GET /transparency/:dbType/:chain/:network/proof/:block_index returns 403 in client mode", + "Integration: REST API GET /transparency/:dbType/:chain/:network/proof/:block_index returns 404 for unknown chain/network", + "Integration: REST API GET /transparency/:dbType/:chain/:network/proof/:block_index returns Merkle inclusion proof for a committed block" + ], + "5bb658138a2834df": [ + "E2E: Disconnect/Resume Parity 10.1 Resume parity vs a control replica a resumed replica converges byte-identically to one that never disconnected", + "resume-parity before-all stub watchdog leaves a normal, on-time stub in place (cancel path never abandons it)", + "resume-parity before-all stub watchdog skips the stub once abandoned before it was ever applied, leaving console stubbable", + "resume-parity before-all stub watchdog undoes an already-applied stub once abandoned, leaving console stubbable" + ], + "5bfa00fa6ab5f2b4": [ + "armed map v2: falsification on temp trees a copied tree reads the same v2 as this checkout, so the harness measures the real thing", + "armed map v2: falsification on temp trees a deleted registry row makes boot throw, v2 UNREADABLE and the completeness suite red", + "armed map v2: falsification on temp trees a shared row outside sync membership does not move the sync fingerprint", + "armed map v2: falsification on temp trees does not move under the regtest venue arming environment (no sync carrier reads it)", + "armed map v2: falsification on temp trees holds under a comment, a registry reformat, a carrier rename and a move", + "armed map v2: falsification on temp trees moves when NOT-YET-PINNED (null) becomes the UNARMED sentinel", + "armed map v2: falsification on temp trees moves when one committed height changes, and names that row alone", + "armed map v2: falsification on temp trees reads the same value without node_modules because every registry row is local data" + ], + "5cb20fdb5738741b": [ + "ClientSync: decoder completeness check on a truncated replica full-history decoder: no windowed exclusion, caller excludes pass through unchanged @regression", + "ClientSync: decoder completeness check on a truncated replica truncated decoder: block-windowed tables are excluded from the count check, lookups stay strict @regression" ], "5cc2b8143bdd5808": [ "Security: remediated dependency advisories @regression @tier4 ADV-10: the installed mariadb reports a patched runtime version", @@ -803,46 +1386,219 @@ "Security: remediated dependency advisories @regression @tier4 ADV-4: brace-expansion survives the CVE-2026-14257 unbounded-length input", "Security: remediated dependency advisories @regression @tier4 ADV-5: the installed axios reports a patched runtime version" ], + "5ccec02617fb694b": [ + "ClientSync: misc branch coverage clearHalt: logs error when db.clearHalt throws", + "ClientSync: misc branch coverage clearHalt: logs without \"was halted\" when _halted is null", + "ClientSync: misc branch coverage constructor: validatorId falls back to \"unknown\" when hostname() is empty", + "ClientSync: misc branch coverage flushHeartbeat: swallows ws.send error", + "ClientSync: misc branch coverage haltOnDivergence: logs on recordHalt failure but still halts in memory", + "ClientSync: misc branch coverage haltOnDivergence: uses defaults when mismatches/sources are falsy", + "ClientSync: misc branch coverage safeParse: returns raw string when JSON.parse fails", + "ClientSync: misc branch coverage verifyRecompute: returns null for decoder dbType", + "ClientSync: misc branch coverage verifyTableCounts: treats NaN local count as 0" + ], + "5d10b0ffea8843e3": [ + "ClientSync isSourceHeightStale reports stale once the window elapses with no new event", + "ClientSync isSourceHeightStale returns false immediately after an event", + "ClientSync isSourceHeightStale returns null before any WS event is seen", + "ClientSync isSourceHeightStale stays fresh within the staleness window" + ], + "5d1de29605d15857": [ + "ClientSync: oversized catch-up fallback routes by truncation full-history replica: size error still routes to bootstrapFromSnapshot (unchanged) @regression", + "ClientSync: oversized catch-up fallback routes by truncation truncated replica: size error routes to bootstrapFromHeightRetry, NOT the full snapshot @regression" + ], "5d511d8452dc7256": [ "protocolAddressRoles cross-repo byte-identity (consensus) @regression canonicalizes every special address identically to the indexer", "protocolAddressRoles cross-repo byte-identity (consensus) @regression carries a bridge escrow role for every ordered coin pair", "protocolAddressRoles cross-repo byte-identity (consensus) @regression passes a non-special address through unchanged on both sides", "protocolAddressRoles cross-repo byte-identity (consensus) @regression snapshot equals the indexer config-derived ROLE_BY_ADDRESS" ], - "631fe6ded689ba09": [ - "ClientSync: VERIFY_RECOMPUTE=false is declared unsafe @regression stays quiet when recompute is enabled", - "ClientSync: VERIFY_RECOMPUTE=false is declared unsafe @regression warns UNSAFE at construction when explicitly disabled", - "ClientSync: bulk-range boundary recompute fails CLOSED @regression HALTS (boundary-read-error) when the committed hash READ fails on every retry @regression", - "ClientSync: bulk-range boundary recompute fails CLOSED @regression HALTS (local-recompute-divergence) on a boundary hash mismatch", - "ClientSync: bulk-range boundary recompute fails CLOSED @regression HALTS (recompute-error) when the recompute errors on every retry", - "ClientSync: bulk-range boundary recompute fails CLOSED @regression does NOT halt when a transient READ error clears within the retries @regression", - "ClientSync: bulk-range boundary recompute fails CLOSED @regression does NOT halt when a transient error clears within the retries", - "ClientSync: bulk-range boundary recompute fails CLOSED @regression reads the committed boundary hash FAIL-CLOSED (rethrow), not on the fail-soft default @regression", - "ClientSync: bulk-range boundary recompute fails CLOSED @regression skips (no halt) when the committed boundary hash is not yet resolvable", - "ClientSync: bulk-range boundary recompute fails CLOSED @regression the LIVE path still fails open: a persistent error does not throw without failClosed", - "ClientSync: divergence halt @regression _haltOnDivergence sets the halt, persists it durably, and clears pending hashes", - "ClientSync: divergence halt @regression a halted client REFUSES to apply blocks", - "ClientSync: divergence halt @regression a prior uncleared halt in sync_halt keeps the client halted on start (no silent resume)", - "ClientSync: divergence halt @regression clearHalt resumes the client and clears the durable record", - "ClientSync: divergence halt @regression clearing a halt-state-check-failed state does not wipe the unread sync_halt row", - "ClientSync: divergence halt @regression is idempotent: a second divergence does not double-record or change the halt block", - "ClientSync: divergence halt @regression re-reads the halt table while idling, so a recovered database is not stalled forever", - "ClientSync: divergence halt @regression starts healthy (not halted)", - "ClientSync: divergence halt @regression stays HALTED (idle, no catch-up) when the start-time halt check throws", - "ClientSync: independent recompute halt @regression HALTS when replicated rows do not hash to the committed block hash", - "ClientSync: independent recompute halt @regression a recompute DB error is logged but does NOT halt (no self-inflicted fork on infra faults)", - "ClientSync: independent recompute halt @regression does NOT halt when rows hash to the committed block hash (clean block advances)", - "ClientSync: independent recompute halt @regression skips recompute when VERIFY_RECOMPUTE is disabled (opt-out for plain replicas)", - "ClientSync: state_hash apply-time integrity halt @regression HALTS when the apply-time state_hash recompute disagrees with the source", - "ClientSync: state_hash apply-time integrity halt @regression SKIPS the check (no recompute, no halt) when the source sent a NULL state_hash (pre-feature block)", - "ClientSync: state_hash apply-time integrity halt @regression does NOT halt when the recomputed state_hash matches (clean block advances)", - "ClientSync: state_hash apply-time integrity halt @regression opts out cleanly when VERIFY_STATE_HASH=false (throwaway mirrors)" + "5fd53912b63d1fe2": [ + "ClientSync: checkpoint-quorum rotation following @regression HALTS when a rotated checkpoint is not signed by the authoritative set (forged quorum)", + "ClientSync: checkpoint-quorum rotation following @regression HALTS when a rotated checkpoint's committed state_root disagrees with the recompute", + "ClientSync: checkpoint-quorum rotation following @regression HALTS when the replica's recompute disagrees with the pinned seed (different chain)", + "ClientSync: checkpoint-quorum rotation following @regression does NOT halt (waits) when the rotated set's snapshot is not yet attested", + "ClientSync: checkpoint-quorum rotation following @regression does NOT halt (waits) when the seed height is not yet recomputed locally", + "ClientSync: checkpoint-quorum rotation following @regression does NOT halt on a transport error while fetching the checkpoint range", + "ClientSync: checkpoint-quorum rotation following @regression follows the pinned seed forward to a rotated checkpoint and does NOT halt" + ], + "5ff54077cc3ba86f": [ + "ClientSync: incrementalCatchUp coalescing calls runIncrementalCatchUp once when no in-flight", + "ClientSync: incrementalCatchUp coalescing does not re-run when pending but no progress was made", + "ClientSync: incrementalCatchUp coalescing re-runs once when _catchUpPending and progress was made", + "ClientSync: incrementalCatchUp coalescing sets _catchUpPending when already in-flight" + ], + "606dc37fb546bda6": [ + "ClientSync runIncrementalCatchUp schema self-heal does not retry when the retry would hit the heal debounce", + "ClientSync runIncrementalCatchUp schema self-heal heals and retries ONCE when the catch-up apply hits a missing table" + ], + "62101a3cfb162f48": [ + "ServerPoller buildBlockPayload builds complete payload with correct structure", + "ServerPoller buildBlockPayload fails closed on a TRANSIENT per-table read error (deadlock 1213) so the block is retried, not broadcast incomplete @regression", + "ServerPoller buildBlockPayload includes a sync_meta transparency row in the indexer payload", + "ServerPoller buildBlockPayload includes block-scoped table rows in data", + "ServerPoller buildBlockPayload keeps state_hash when the view tip IS the block (steady state) or is unknown", + "ServerPoller buildBlockPayload merges derived anchor/archive rewards (block_index = earn-block E, derive_block_index = this block) into validator_rewards", + "ServerPoller buildBlockPayload omits sync_meta from the decoder payload", + "ServerPoller buildBlockPayload returns null when block hash row is missing", + "ServerPoller buildBlockPayload ships state_hash NULL for burst-built blocks (viewTip ahead of B)", + "ServerPoller buildBlockPayload ships state_root NULL for burst blocks but keeps balances/merkle roots (@regression)", + "ServerPoller buildBlockPayload skips a per-table SCHEMA-GAP read error (errno 1146) and still builds the block @regression", + "ServerPoller buildBlockPayload streams contract_emissions via getEmissionRowsForBlock, not getActionScopedRows" + ], + "634548f3f3a46e14": [ + "E2E: Decoder dispensers reconcile Nth-catch-up cadence: every=1 reconciles drift away; a high `every` leaves it (no error)", + "E2E: Decoder dispensers reconcile a full-snapshot bootstrap seeds dispensers to parity; reconcile is idempotent", + "E2E: Decoder dispensers reconcile converges a drifted replica: hard-purge + soft-expire + insert all mirror on reconcile" + ], + "6362e6d5b508b99d": [ + "BlockBroadcaster getValidatorHeartbeats counts only the unknown-lag validators in unknown_count across a mixed set", + "BlockBroadcaster getValidatorHeartbeats marks a validator known with a computed lag once source height is set", + "BlockBroadcaster getValidatorHeartbeats marks a validator unknown when source height is not yet known", + "BlockBroadcaster getValidatorHeartbeats reports a caught-up validator as known with lag 0", + "BlockBroadcaster getValidatorHeartbeats returns empty structure with zero counts when no validators reported" + ], + "637056de9db4317f": [ + "ClientSync: bootstrapFromSnapshot applies the full snapshot under the shared write lock (M-21)", + "ClientSync: bootstrapFromSnapshot catch/retry: rotates sources and THROWS on repeated failure (no swallow)", + "ClientSync: bootstrapFromSnapshot decoder + 2 sources calls verifyDecoderCompleteness", + "ClientSync: bootstrapFromSnapshot happy path with gzipped buffer", + "ClientSync: bootstrapFromSnapshot happy path with raw (non-gzipped) buffer", + "ClientSync: bootstrapFromSnapshot indexer + 2 sources + VERIFY_HASHES calls verifyAgainstSource", + "ClientSync: bootstrapFromSnapshot retries the single configured source with backoff, then succeeds", + "ClientSync: bootstrapFromSnapshot single source exhausted: THROWS instead of returning success", + "ClientSync: bootstrapFromSnapshot throws (does not silently return) when no sources configured", + "ClientSync: fetchAndApplySchema calls addMissingColumns when table already exists", + "ClientSync: fetchAndApplySchema creates a table that does not yet exist", + "ClientSync: fetchAndApplySchema logs outer catch when axios.get rejects", + "ClientSync: fetchAndApplySchema rejects invalid DDL (not CREATE TABLE) and continues", + "ClientSync: fetchAndApplySchema rejects invalid table name (e.g. bad-name) and continues", + "ClientSync: fetchAndApplySchema skips table with empty/falsy createSql", + "ClientSync: fetchAndApplySchema swallows per-table doQuery error and continues" + ], + "654c349590fc25ab": [ + "SnapshotBuilder streamDispensers rejects instead of shipping an empty dump when the source read fails @regression", + "SnapshotBuilder streamDispensers rejects on a failed read in the cursor branch too @regression" + ], + "65bb959e23b70c91": [ + "03 Bootstrap Apply bootstrap 100 blocks (baseline)", + "03 Bootstrap Apply bootstrap 100 blocks with 10 actions each", + "03 Bootstrap Apply bootstrap 50 blocks with 50 actions each (heavy)", + "03 Bootstrap Apply bootstrap 500 blocks", + "03 Bootstrap Apply data integrity after bootstrap" + ], + "665052ac9fa042e3": [ + "ClientSync: verifyDecoderCompleteness catch logs \"Decoder completeness check failed\" when axios.get rejects" + ], + "675159dfa1a4a4c2": [ + "bin/lib/carrier_logic_pin.js: --retire and --move (h) --retire removes the entry and records a move to nothing", + "bin/lib/carrier_logic_pin.js: --retire and --move (i) --move keeps the id and hash, repoints the path, and records both paths", + "bin/lib/carrier_logic_pin.js: --retire and --move (j) --move is refused when the new path carries different logic, and the pin is untouched", + "bin/lib/carrier_logic_pin.js: the records rule (b) accepts and refuses (k) accepts a retire record with to: null and a move record naming the new path", + "bin/lib/carrier_logic_pin.js: the records rule (b) accepts and refuses (l) refuses a retire with no record, naming the id", + "bin/lib/carrier_logic_pin.js: the records rule (b) accepts and refuses (m) refuses a move with no path record, even under a same-hash --write record", + "bin/lib/carrier_logic_pin.js: the records rule (b) accepts and refuses (n) still refuses a changed hash and an addition without a record", + "bin/lib/carrier_logic_pin.js: tokenHash (f) ignores a comment, a reformat and a require path, and moves on an operator", + "bin/lib/carrier_logic_pin.js: tokenHash keys an entry by its stem under src/, without the extension", + "bin/pins/carrier-logic.json: the carrier logic pin (a) every entry hashes to its pin", + "bin/pins/carrier-logic.json: the carrier logic pin (b) every entry that changed, left or moved since HEAD carries a record", + "bin/pins/carrier-logic.json: the carrier logic pin (c) every twin id hashes the same in the sibling pin", + "bin/pins/carrier-logic.json: the carrier logic pin (d) the digest is stable and matches the CLI", + "bin/pins/carrier-logic.json: the carrier logic pin (e) every twin file's bytes equal every sibling copy", + "bin/pins/carrier-logic.json: the carrier logic pin (g) the membership rule and the pin name the same files, both ways" + ], + "677fde3e236166c4": [ + "ClientRollback rollback clears escrow when no offer survives (orphaned offer / SET direction)", + "ClientRollback rollback contract slash-restore tiebreaks on (execution_index, slash_position), byte-matching the source (not AUTO_INCREMENT id)", + "ClientRollback rollback does not throw if the escrow re-derive tables are missing (older replica schema)", + "ClientRollback rollback re-derives escrow AFTER the action-scoped deletes", + "ClientRollback rollback re-stamps escrow to a surviving open offer (orphaned release / CLEAR direction)", + "ClientRollback rollback replays BOTH polls resets: the re-open (callback_due_block re-NULLed) and the timelock re-fire reset", + "ClientRollback rollback replays the anchor reconcile-log restore into validator_rewards (block_index-keyed, before deletes) (RB-ANCHOR)", + "ClientRollback rollback replays the attests and xcalls request_status resets (block_index-keyed)", + "ClientRollback rollback replays the delegation-rotation key restore into contract_stakes (block_index-keyed, before deletes)", + "ClientRollback rollback replays the slash-debit restore for both stake tables (block_index-keyed, before deletes)", + "ClientRollback rollback runs the in-place resets before the action-scoped deletes", + "ClientRollback rollback skips the in-place resets and the escrow re-derive when firstActionIndex is null", + "ClientRollback rollback still replays the anchor reconcile-log restore when firstActionIndex is null (RB-ANCHOR-NULL)" + ], + "6825350ea939c1f3": [ + "ClientSync start bootstraps from a full snapshot when the replica is empty", + "ClientSync start does NOT reconcile schema on the empty-replica bootstrap path (bootstrap fetches it itself)", + "ClientSync start passes lastAppliedBlock + 1 to incremental catch-up when resuming a populated replica", + "ClientSync start reconciles the source schema on resume, BEFORE catch-up (creates zero-row tables added post-bootstrap)" ], "685672ba7325e614": [ "replica secondary-index ensure list carries state_tree_roots.block_index, which ClientRollback's range delete needs", "replica secondary-index ensure list every ensured index is declared in that table's schema definition", "replica secondary-index ensure list sanity: the gate actually parses entries (it cannot pass vacuously)" ], + "68687be53be6c143": [ + "HubClient constructor builds the correct URL", + "HubClient getallconfigs returns null on error", + "HubClient getallconfigs returns null when no result in response", + "HubClient getallconfigs returns parsed result on success", + "HubClient ping returns false on error", + "HubClient ping returns falsy when result is null", + "HubClient ping returns true on successful response", + "HubClient ping sends correct JSON-RPC payload" + ], + "68f10a273308ebbe": [ + "Integration: REST API Proxy-trust rate-limit wiring collapses every caller onto the socket address when TRUST_PROXY is off", + "Integration: REST API Proxy-trust rate-limit wiring gives independent snapshot buckets to distinct forwarded clients when TRUST_PROXY is on" + ], + "6aba3ac215f51b2b": [ + "ClientSync.oraclePublishSetAt uses the as-of reconstruction (#4927) calls getStakeWeightsByCapabilityAsOf, not the live getStakeWeightsByCapability", + "Database.getStakeWeightsByCapabilityAsOf (#4927) REFUSES a null weight rather than defaulting it to \"0\"", + "Database.getStakeWeightsByCapabilityAsOf (#4927) adds back post-snapshot stakes slash debits in the weight subquery", + "Database.getStakeWeightsByCapabilityAsOf (#4927) binds the add-back snapshot block FIRST, then the base arg sequence, then LIMIT", + "Database.getStakeWeightsByCapabilityAsOf (#4927) does not reference _stakeWeightsSql (keeps the drift-guarded twin untouched)", + "Database.getStakeWeightsByCapabilityAsOf (#4927) maps rows to {pubkey, source, weight}", + "Database.getStakeWeightsByCapabilityAsOf (#4927) passes minStake through to the HAVING floor as a string", + "Database.getStakeWeightsByCapabilityAsOf (#4927) placeholder count equals the bound-arg count (arg-order drift guard)", + "Database.getStakeWeightsByCapabilityAsOf (#4927) returns [] when the valid status id cannot be resolved (no query run)" + ], + "6aff270db2df60a7": [ + "XCHAIN_ESC locked leaf: the \u00a77 shadow thread @regression the shadow value never reaches a committed column (source pin, both twins)", + "XCHAIN_ESC locked leaf: the \u00a77 shadow thread @regression threading equals a fresh build of the same leaf set (spendable + locked)" + ], + "6c7b6eb10f3ced0f": [ + "Chaos: Sync Resilience CE-SYNC-01: Server Crash \u2192 Reconnect \u2192 Gap Healing client recovers from server crash and heals block gap", + "Chaos: Sync Resilience CE-SYNC-02: Block Gap Detection \u2192 Incremental Catch-Up client detects and heals a multi-block gap via status event", + "Chaos: Sync Resilience CE-SYNC-03: Reorg During Active Sync client handles reorg while source DB has injected latency", + "Chaos: Sync Resilience CE-SYNC-04: Compound Failure (Source Down + Server Crash) full data integrity after compound source outage + server crash" + ], + "6cd305fd75432e2c": [ + "SnapshotBuilder transactional boundary full: commits (releases) the snapshot even on the 404 empty-db path", + "SnapshotBuilder transactional boundary full: opens read snapshot before reading the block anchor", + "SnapshotBuilder transactional boundary full: rolls back the snapshot if a read throws before streaming", + "SnapshotBuilder transactional boundary incremental: commits (releases) the snapshot on the 404 path", + "SnapshotBuilder transactional boundary incremental: opens read snapshot before reading the block anchor" + ], + "6d955dc4007ee59e": [ + "contract_state_root: strict reads @regression a faulting touched-key read THROWS rather than threading the block forward unchanged", + "contract_state_root: strict reads @regression every derivation read goes through doQueryStrict, never doQuery" + ], + "6e98846a4e3b9709": [ + "ClientSync: verifyAgainstSource calls haltOnDivergence when VERIFY_RECOMPUTE=true and recompute has mismatches", + "ClientSync: verifyAgainstSource halts on a confirmed same-height cross-source hash mismatch when HALT_ON_DIVERGENCE is on", + "ClientSync: verifyAgainstSource logs \"HASH MISMATCH\" when hashes differ", + "ClientSync: verifyAgainstSource logs \"Hash verification failed\" when axios.get rejects", + "ClientSync: verifyAgainstSource logs \"Hash verification passed\" when hashes match", + "ClientSync: verifyAgainstSource logs \"Table-count verification passed\" when counts match", + "ClientSync: verifyAgainstSource logs TABLE_COUNT_MISMATCH when source has more rows", + "ClientSync: verifyAgainstSource returns early when dbType is decoder", + "ClientSync: verifyAgainstSource returns early when localHashes is null", + "ClientSync: verifyAgainstSource skips the cross-source hash check on tip skew (no spurious HASH MISMATCH, no halt)" + ], + "6f3bf3f9c5f1d95a": [ + "XCHAIN_ESC locked leaf: strict reads @regression a faulting live-set read THROWS rather than rebuilding balances_root with no locked leaves", + "XCHAIN_ESC locked leaf: strict reads @regression a faulting per-key read THROWS rather than DELETING the leaf (delete-on-zero)", + "XCHAIN_ESC locked leaf: strict reads @regression a faulting touched-key read THROWS rather than leaving the locked leaves stale", + "XCHAIN_ESC locked leaf: strict reads @regression every journal read goes through doQueryStrict, never doQuery", + "XCHAIN_ESC locked leaf: the \u00a77 shadow thread @regression no prior shadow root: full-builds through the caller callback (window start)", + "XCHAIN_ESC locked leaf: the \u00a77 shadow thread @regression null balanceUpdates (committed path full-recomputed) forces the shadow full build too" + ], "6f8cd171d7d29aa7": [ "consensus block-hash conformance twins (static drift-lock) @regression BLOCK_HASH_VERSION is identical across BlockHasher.js and indexer db/shared.js", "consensus block-hash conformance twins (static drift-lock) @regression DbNodeStore and MemoryNodeStore are BYTE-identical (node-store twin)", @@ -855,69 +1611,32 @@ "consensus block-hash conformance twins (static drift-lock) @regression the hash-assembly tail (chaining + hash_version fold) is identical", "consensus block-hash conformance twins (static drift-lock) @regression utility jsonStringify + getDataHash (shared preimage serializer) are identical" ], - "71d730e75a4de5ea": [ - "ClientRollback _rollbackDecoder aborts (fail-closed) on a transient error in a tx-scoped delete (item 1848)", - "ClientRollback _rollbackDecoder deletes tx-scoped tables by tx_index, then block-scoped tables by block_index", - "ClientRollback _rollbackDecoder rolls back and rethrows when a block-scoped delete fails", - "ClientRollback _rollbackDecoder routes a decoder DB through _rollbackDecoder", - "ClientRollback _rollbackDecoder skips tx-scoped deletes when no transactions are in range", - "ClientRollback _rollbackDecoder swallows a missing tx-scoped table error (schema gap) and still completes", - "ClientRollback balance-rebuild error handling logs (does not rethrow) a 1146 error from rebuildBalances", - "ClientRollback balance-rebuild error handling logs (does not rethrow) a 1146 error from recomputeTokenSupplies", - "ClientRollback balance-rebuild error handling recomputes token supplies after rebuilding balances (before commit)", - "ClientRollback balance-rebuild error handling rethrows a non-1146 error from rebuildBalances", - "ClientRollback balance-rebuild error handling rethrows a non-1146 error from recomputeTokenSupplies", - "ClientRollback pair-scoped markets rollback (IDX-2 mirror) aborts (fail-closed) on a transient error in the pair-scoped sweep", - "ClientRollback pair-scoped markets rollback (IDX-2 mirror) collects the affected pairs BEFORE the action-scoped delete removes them", - "ClientRollback pair-scoped markets rollback (IDX-2 mirror) deletes a market whose pair kept no surviving order or match", - "ClientRollback pair-scoped markets rollback (IDX-2 mirror) keeps the market when a surviving order still references the pair", - "ClientRollback pair-scoped markets rollback (IDX-2 mirror) keeps the market when only an order_match survives", - "ClientRollback pair-scoped markets rollback (IDX-2 mirror) skips the sweep on a truncated replica", - "ClientRollback pair-scoped markets rollback (IDX-2 mirror) swallows a schema gap in the pair-scoped sweep", - "ClientRollback rollback aborts (fail-closed) on a transient error in the contract_emissions delete", - "ClientRollback rollback aborts (fail-closed) on a transient error in the icons orphan-sweep", - "ClientRollback rollback aborts (fail-closed) on a transient error in the merkle_epochs reorg delete", - "ClientRollback rollback aborts (fail-closed) on a transient error in the sync_meta reorg delete", - "ClientRollback rollback aborts before the transaction when the first-action read faults", - "ClientRollback rollback aborts before the transaction when the market-pair read faults", - "ClientRollback rollback aborts the rollback (fail-closed) on a transient error in a generic DELETE loop", - "ClientRollback rollback aborts the rollback on a transient error in the blockTables loop", - "ClientRollback rollback clears escrow when no offer survives (orphaned offer / SET direction)", - "ClientRollback rollback contract slash-restore tiebreaks on (execution_index, slash_position), byte-matching the source (not AUTO_INCREMENT id)", - "ClientRollback rollback deletes contract_emissions first", - "ClientRollback rollback deletes from action-scoped tables with action_index", - "ClientRollback rollback deletes from block-scoped tables with block_index", - "ClientRollback rollback deletes from merkle_epochs by end_block, mirroring the server pruneFrom (item 4770)", - "ClientRollback rollback deletes from sync_meta", - "ClientRollback rollback deletes validator_rewards by derive_block_index as well, mirroring the source", - "ClientRollback rollback does not throw if the escrow re-derive tables are missing (older replica schema)", - "ClientRollback rollback gets first action index for the block", - "ClientRollback rollback handles per-table errors gracefully (table may not exist)", - "ClientRollback rollback prunes the hub-mirrored per-action tables scoped to this chain and firstActionIndex", - "ClientRollback rollback re-derives escrow AFTER the action-scoped deletes", - "ClientRollback rollback re-stamps escrow to a surviving open offer (orphaned release / CLEAR direction)", - "ClientRollback rollback reads the affected market pairs fail-CLOSED (opts.rethrow)", - "ClientRollback rollback reads the first action index fail-CLOSED (opts.rethrow)", - "ClientRollback rollback recalculates balances from credits/debits", - "ClientRollback rollback replays BOTH polls resets: the re-open (callback_due_block re-NULLed) and the timelock re-fire reset", - "ClientRollback rollback replays the anchor reconcile-log restore into validator_rewards (block_index-keyed, before deletes) (RB-ANCHOR)", - "ClientRollback rollback replays the attests and xcalls request_status resets (block_index-keyed)", - "ClientRollback rollback replays the delegation-rotation key restore into contract_stakes (block_index-keyed, before deletes)", - "ClientRollback rollback replays the slash-debit restore for both stake tables (block_index-keyed, before deletes)", - "ClientRollback rollback restores a stamped ATTEST v5 batch head before the action-scoped deletes", - "ClientRollback rollback rolls back transaction on error and rethrows", - "ClientRollback rollback runs the in-place resets before the action-scoped deletes", - "ClientRollback rollback skips action-scoped deletes when firstActionIndex is null", - "ClientRollback rollback skips the ATTEST batch-head restore when firstActionIndex is null (no orphaned continuation)", - "ClientRollback rollback skips the in-place resets and the escrow re-derive when firstActionIndex is null", - "ClientRollback rollback still deletes the cross_chain mirrors when bridge_transfers is missing (errno 1146)", - "ClientRollback rollback still replays the anchor reconcile-log restore when firstActionIndex is null (RB-ANCHOR-NULL)", - "ClientRollback rollback still skips the market sweep on a schema gap (errno 1146)", - "ClientRollback rollback swallows a schema gap on the ATTEST batch-head restore but aborts on a transient fault", - "ClientRollback rollback swallows missing-table errors on every optional delete + the generic loops", - "ClientRollback rollback wraps everything in a transaction", - "ClientRollback table lists has 12 block-scoped tables", - "ClientRollback table lists has action-scoped data tables" + "6fe6527e42a197a6": [ + "ClientSync persistent replica gaps ages decoder shortfalls from the periodic path only", + "ClientSync persistent replica gaps does not clear a tracked gap on a sweep that never completed", + "ClientSync persistent replica gaps does not escalate a shortfall seen on a single sweep", + "ClientSync persistent replica gaps escalates a shortfall that survives consecutive equal-height sweeps", + "ClientSync persistent replica gaps rate-limits the alert but re-raises immediately when the gap grows", + "ClientSync persistent replica gaps records the persistent gap durably and clears it when the gap closes", + "ClientSync persistent replica gaps reports that the client self-repair pass failed to close a short lookup" + ], + "71dbe5f3ab51e1b0": [ + "ServerPoller updateStatus calls broadcaster.updateStatus with correct shape", + "ServerPoller updateStatus handles null lastPolledBlock", + "ServerPoller updateStatus replication freshness fails closed when the read throws", + "ServerPoller updateStatus replication freshness fails closed when the replication status is unreadable", + "ServerPoller updateStatus replication freshness reports fresh on a primary (not a replica at all)", + "ServerPoller updateStatus replication freshness reports fresh on a replica inside the lag ceiling", + "ServerPoller updateStatus replication freshness reports stale past the lag ceiling", + "ServerPoller updateStatus replication freshness reports stale when the SQL thread stopped (Seconds_Behind NULL)", + "ServerPoller updateStatus stamps measured_at on a successful measurement, and publishes nothing on a failed one" + ], + "72c2cac4e73d4e53": [ + "SnapshotBuilder streamFullSnapshot emits every row of a keyless table exactly once in a single ordered pass (no offset re-paging)", + "SnapshotBuilder streamFullSnapshot returns 404 when no blocks in database", + "SnapshotBuilder streamFullSnapshot sets correct response headers", + "SnapshotBuilder streamFullSnapshot skips tables with 0 rows", + "SnapshotBuilder streamFullSnapshot streams valid gzip JSON for tables with data" ], "73126c25800a9bdc": [ "ClientApplier surrogate-id registry matches the indexer DDL @regression every allow-listed table carries a reason, so the list cannot grow silently", @@ -948,62 +1667,32 @@ "replication schema version and migration frontier @regression indexer: the frontier date is a well-formed migration date", "replication schema version and migration frontier @regression indexer: the frontier does not run ahead of the migration ledger" ], - "75fa9b19165be9cf": [ - "BlockBroadcaster _send clears the backpressure stall window when the buffer drains (item 5410)", - "BlockBroadcaster _send closes ws when the send buffer exceeds the byte ceiling (item 5410)", - "BlockBroadcaster _send skips non-OPEN WebSocket", - "BlockBroadcaster addSubscription adds ws to subscribers set", - "BlockBroadcaster addSubscription does not send status if none available", - "BlockBroadcaster addSubscription registers close and error handlers", - "BlockBroadcaster addSubscription rejects when per-IP limit exceeded", - "BlockBroadcaster addSubscription sends initial status if available", - "BlockBroadcaster addSubscription sets metadata on ws", - "BlockBroadcaster addSubscription uses x-forwarded-for when TRUST_PROXY is true", - "BlockBroadcaster applied-block tracking does not advance _syncLastSentBlock for non-block events", - "BlockBroadcaster applied-block tracking ignores a heartbeat with a non-integer/negative/infinite appliedBlock", - "BlockBroadcaster applied-block tracking ignores malformed or unknown inbound messages", - "BlockBroadcaster applied-block tracking initialises _syncLastSentBlock and _syncAppliedBlock to null", - "BlockBroadcaster applied-block tracking reports heartbeatReceived true even when caught up (lag 0)", - "BlockBroadcaster applied-block tracking reports lag = lastSentBlock - appliedBlock after a heartbeat", - "BlockBroadcaster applied-block tracking reports null appliedBlock and lag for a subscriber with no heartbeat", - "BlockBroadcaster applied-block tracking returns an empty array for an unknown chain/network", - "BlockBroadcaster applied-block tracking updates _syncAppliedBlock when a heartbeat message arrives", - "BlockBroadcaster applied-block tracking updates _syncLastSentBlock to the block height on broadcast", - "BlockBroadcaster broadcast does not send to other chain/network", - "BlockBroadcaster broadcast does nothing when no subscribers", - "BlockBroadcaster broadcast encodes binary columns in the updated_rows channel (same wire codec as data)", - "BlockBroadcaster broadcast infra-only subscriber receives only infra tables, filtered from event.data", - "BlockBroadcaster broadcast infra-only subscriber receives the infra subset of updated_rows", - "BlockBroadcaster broadcast infra-only subscriber with no matching infra tables gets an empty data set (not the full block)", - "BlockBroadcaster broadcast sends to all subscribers of a chain/network", - "BlockBroadcaster broadcastStatus does nothing when no status data", - "BlockBroadcaster broadcastStatus sends status to all subscribers", - "BlockBroadcaster evictStaleValidators hard-removes a non-roster entry that stays stale past a second TTL window", - "BlockBroadcaster evictStaleValidators keeps a roster member visible as stale indefinitely", - "BlockBroadcaster evictStaleValidators leaves a fresh entry untouched", - "BlockBroadcaster evictStaleValidators restores a stale validator to known/unknown on the next heartbeat", - "BlockBroadcaster evictStaleValidators transitions an entry past the TTL to stale instead of deleting it", - "BlockBroadcaster getStatus freshness expiry broadcastStatus publishes the expired verdict, not the cached healthy one", - "BlockBroadcaster getStatus freshness expiry does not mutate the cached object, so a recovered poll is not poisoned", - "BlockBroadcaster getStatus freshness expiry expires the freshness verdict of a status measured before the poller stopped", - "BlockBroadcaster getStatus freshness expiry leaves an UNDATED status alone rather than demoting on a guess", - "BlockBroadcaster getStatus freshness expiry returns a freshly measured status unchanged", - "BlockBroadcaster getSubscriberCount returns 0 for unknown chain/network", - "BlockBroadcaster getSubscriberCount returns count for specific chain/network", - "BlockBroadcaster getSubscriberCount returns total across all chains when no args", - "BlockBroadcaster getValidatorHeartbeats counts only the unknown-lag validators in unknown_count across a mixed set", - "BlockBroadcaster getValidatorHeartbeats marks a validator known with a computed lag once source height is set", - "BlockBroadcaster getValidatorHeartbeats marks a validator unknown when source height is not yet known", - "BlockBroadcaster getValidatorHeartbeats reports a caught-up validator as known with lag 0", - "BlockBroadcaster getValidatorHeartbeats returns empty structure with zero counts when no validators reported", - "BlockBroadcaster getValidatorHeartbeats with an expected-validator roster does not duplicate a reporting roster member as absent", - "BlockBroadcaster getValidatorHeartbeats with an expected-validator roster reports a non-roster reporter alongside absent roster members", - "BlockBroadcaster getValidatorHeartbeats with an expected-validator roster reports all roster members absent when none have reported", - "BlockBroadcaster getValidatorHeartbeats with an expected-validator roster surfaces roster members that have never reported as status absent", - "BlockBroadcaster removeSubscription cleans up empty sets from maps", - "BlockBroadcaster removeSubscription clears metadata on ws", - "BlockBroadcaster removeSubscription handles ws with no metadata gracefully", - "BlockBroadcaster removeSubscription removes from subscribers and ipConnections" + "7435d3e8a1e6d309": [ + "Tier 3 - config.getConfig @tier3 VERIFY_HASHES is always a boolean", + "Tier 3 - config.getConfig @tier3 VERIFY_HASHES is false only when env var is exactly \"false\" (case-insensitive)", + "Tier 3 - config.getConfig @tier3 crash safety never throws for any combination of env var values", + "Tier 3 - config.getConfig @tier3 hardcoded constants are never overridden by env vars", + "Tier 3 - config.getConfig @tier3 return shape always returns an object with all required keys", + "Tier 3 - config.getConfig @tier3 return shape numeric fields are always integers", + "Tier 3 - config.getConfig @tier3 return shape numeric fields respect minimum values" + ], + "7594e07757fb9953": [ + "HubClient getIndexerConfigs defaults db_host to 127.0.0.1 when neither present", + "HubClient getIndexerConfigs extracts xchain-indexer entries", + "HubClient getIndexerConfigs falls back db_host to host", + "HubClient getIndexerConfigs handles multiple chains", + "HubClient getIndexerConfigs returns empty array when hub returns null", + "HubClient getIndexerConfigs skips empty coin keys", + "HubClient getIndexerConfigs skips networks without xchain-indexer module" + ], + "75e74f104d7e1701": [ + "Database.addMissingColumns: AUTO_INCREMENT key clause adds no key clause for an ordinary column, including one whose COMMENT says auto_increment", + "Database.addMissingColumns: AUTO_INCREMENT key clause appends the source UNIQUE key so the ALTER is not refused with errno 1075", + "Database.addMissingColumns: AUTO_INCREMENT key clause emits an UNQUALIFIED ALTER against the pool default database, so Replicate_Do_DB forwards it", + "Database.addMissingColumns: AUTO_INCREMENT key clause falls back to a UNIQUE key when the replica already has a different primary key", + "Database.addMissingColumns: AUTO_INCREMENT key clause reports a refused ALTER as a failure and never logs \"Added column\"", + "Database.addMissingColumns: AUTO_INCREMENT key clause reproduces a source PRIMARY KEY when the replica has no primary key", + "Database.addMissingColumns: AUTO_INCREMENT key clause synthesises a UNIQUE key when the source declares no single-column key on the auto column" ], "76d8fd79030c9638": [ "ClientApplier strictIgnoreCheck is a no-op by default: no SHOW WARNINGS round trip on the ordinary apply path", @@ -1074,6 +1763,13 @@ "checkpoint-quorum flag-day coupling @regression default is OFF only while pinnedValidators.js is inert, ON once a launch set lands", "checkpoint-quorum flag-day coupling @regression the interval that throttles the anchor stays usable at its default" ], + "7b09ebaa3cd21c00": [ + "SnapshotBuilder streamIncrementalSnapshot lookup paging pages a full-dump lookup table by id cursor instead of one unbounded SELECT *" + ], + "7b5dc0d725692134": [ + "SyncService startServerMode creates broadcaster and snapshotBuilder", + "SyncService startServerMode starts a poller for each discovered database" + ], "7bd37c7fd3de6737": [ "getBlockLeafRows special-address canonicalization (consensus) canonicalizes credit/debit/escrow special addresses to their role token", "getBlockLeafRows special-address canonicalization (consensus) leaves contract source addresses raw (ledger-only canonicalization, mirrors the source)", @@ -1088,215 +1784,99 @@ "stateCommitment.reportOrphanStats (sync twin) @regression @tier2 returns all-zero for an empty store", "stateCommitment.reportOrphanStats (sync twin) @regression @tier2 stops the walk at maxNodes and flags the truncated figure as an estimate" ], - "7ce539894822d70a": [ - "checkpoint_commitment_activation activates at/above the mainnet threshold and is off below it", - "checkpoint_commitment_activation exposes a per-network threshold map with regtest armed from genesis", - "checkpoint_commitment_activation fails closed on malformed input and unknown networks", - "checkpoint_commitment_activation testnet arms at 146000, off one block below (keying-skew fix)" + "7d9682f3a69106c6": [ + "ClientSync handleBlock cross-source verification applies block when two sources match", + "ClientSync handleBlock cross-source verification applies from primary after timeout when only one source responds", + "ClientSync handleBlock cross-source verification arms a timeout when only the non-primary source arrives first", + "ClientSync handleBlock cross-source verification does not apply block when sources have mismatched hashes", + "ClientSync handleBlock cross-source verification does not double-arm the timer when both sources arrive before expiry", + "ClientSync handleBlock decoder fork guard does not false-trigger before any block_hash is stored (fresh boot)", + "ClientSync handleBlock decoder fork guard does not trigger catch-up when the head block re-arrives with the same hash", + "ClientSync handleBlock decoder fork guard rewinds the orphaned head and catches up from the forked height", + "ClientSync handleBlock single source mode applies block immediately without waiting", + "ClientSync handleBlock skips blocks already applied", + "ClientSync handleBlock triggers catch-up on chain continuity failure", + "ClientSync handleBlock verification disabled applies block immediately", + "ClientSync handleBlock verifies chain continuity" ], - "808d4ec2c5ddf345": [ - "Rollback coverage guard @regression ATTEST v5 batch-head status restore is mirrored across xchain-indexer and xchain-sync (bespoke-logic drift guard)", - "Rollback coverage guard @regression COINPay match-status re-derive SQL is identical across xchain-indexer and xchain-sync (cross-repo drift guard)", - "Rollback coverage guard @regression F-1: tokens is not in any updatedRows mutation-class array (supply rides the ledger-driven pass + token_supply hash class)", - "Rollback coverage guard @regression F-2: buildStateHashData includes cooldown-maturity refund credit in credits class (maturity fixture)", - "Rollback coverage guard @regression F-2: buildStateHashData includes the anchor CRC-failure parent in the anchor_invalid preimage class (value fixture)", - "Rollback coverage guard @regression F-2: collectUpdatedRows returns the invalid_archive-stamped anchor parent by value (CRC-failure fixture)", - "Rollback coverage guard @regression F-5: OPERATOR_LOCAL_TABLES equals the registry-derived exclusion set plus the three permitted non-registry names", - "Rollback coverage guard @regression F-5: hub-mirrored tables are absent from the ServerPoller replicated universe (snapshot-exclusion contract)", - "Rollback coverage guard @regression ServerPoller streams index_addresses via the generic *_id pass (non-tx-interned completeness) @regression", - "Rollback coverage guard @regression VOTE polls re-open reset is mirrored across xchain-indexer and xchain-sync (bespoke-logic drift guard)", - "Rollback coverage guard @regression _cappedStakeWeightsSql is identical across xchain-indexer and xchain-sync (cross-repo drift guard)", - "Rollback coverage guard @regression _stakeWeightsSql is identical across xchain-indexer and xchain-sync (cross-repo drift guard)", - "Rollback coverage guard @regression anchor invalid_archive to unverified reset is mirrored across xchain-indexer and xchain-sync (bespoke-logic drift guard)", - "Rollback coverage guard @regression archive-head version set is [1] via the shared stateHash constant, consumed by updatedRows", - "Rollback coverage guard @regression archive_rollback_author_scope_activation.js is byte-identical across xchain-indexer and xchain-sync", - "Rollback coverage guard @regression attests is rolled back on the replica under its consolidated name, not the phantom split names", - "Rollback coverage guard @regression balances is recomputed, not blindly deleted by index", - "Rollback coverage guard @regression contract slash-restore SQL is identical across xchain-indexer and xchain-sync (cross-repo drift guard)", - "Rollback coverage guard @regression contractStateSubtree.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", - "Rollback coverage guard @regression contractStateSubtree.test.js is byte-identical across xchain-sync and xchain-indexer, modulo sibling require depth (cross-repo twin)", - "Rollback coverage guard @regression cooldown-maturity reversal is mirrored across xchain-indexer and xchain-sync (bespoke-logic drift guard)", - "Rollback coverage guard @regression cross-chain mirror reorg delete SQL is identical across xchain-indexer and xchain-sync (cross-repo drift guard)", - "Rollback coverage guard @regression delegations deactivation reset is the threshold form on both sides (bespoke-logic drift guard)", - "Rollback coverage guard @regression demands a known network, because the publisher scope is armed", - "Rollback coverage guard @regression escrow re-derive SQL is identical across xchain-indexer and xchain-sync (cross-repo drift guard)", - "Rollback coverage guard @regression escrowLeafSubtree.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", - "Rollback coverage guard @regression escrowLeafSubtree.test.js is byte-identical across xchain-sync and xchain-indexer, modulo sibling require depth (cross-repo twin)", - "Rollback coverage guard @regression every replicated DECODER table is handled on reorg", - "Rollback coverage guard @regression every replicated INDEXER table is handled on reorg", - "Rollback coverage guard @regression every table the source indexer rolls back is mirrored by ClientRollback (cross-repo drift guard)", - "Rollback coverage guard @regression every utf8mb4 widen entry is carried by a dated xchain-indexer migration (source/replica lockstep)", - "Rollback coverage guard @regression forward cooldown-credit selection mirrors the reverse delete keys (bespoke-logic drift guard)", - "Rollback coverage guard @regression forward derived-reward selection mirrors the derive_block_index rollback key, and the reconcile DELETE is mirrored (bespoke-logic drift guard)", - "Rollback coverage guard @regression forward recovery-reward selection mirrors the rollback key (bespoke-logic drift guard)", - "Rollback coverage guard @regression index id lookups are rolled back on the replica and mirror the source indexer (^id consensus)", - "Rollback coverage guard @regression merkle.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", - "Rollback coverage guard @regression pair-scoped IDX-2 markets deletion is mirrored across xchain-indexer and xchain-sync (parity drift guard)", - "Rollback coverage guard @regression prices is rolled back on the replica (regression: this was the drift that motivated the guard)", - "Rollback coverage guard @regression publisher-scope heights are the 2026-09-09 ruling values", - "Rollback coverage guard @regression registry replica-flagged orphan sweeps are mirrored across xchain-indexer and xchain-sync (parity drift guard)", - "Rollback coverage guard @regression sanity: ServerPoller declares a meaningful indexer table set", - "Rollback coverage guard @regression stake_weight_collation_activation.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", - "Rollback coverage guard @regression stateHash.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", - "Rollback coverage guard @regression stateHash.js selection predicates mirror the replicated mutation classes", - "Rollback coverage guard @regression stateSubtreeActivation.test.js is byte-identical across xchain-sync and xchain-indexer, modulo sibling require depth (cross-repo twin)", - "Rollback coverage guard @regression state_commitment_activation.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", - "Rollback coverage guard @regression state_key_collation_activation.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", - "Rollback coverage guard @regression state_subtree_activation.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", - "Rollback coverage guard @regression state_subtree_activation.js is byte-identical in xchain-explorer too (escrow-leaf liveness refusal)", - "Rollback coverage guard @regression state_subtree_activation.js is byte-identical in xchain-sdk too (client liveness export)", - "Rollback coverage guard @regression stream:special bucket tables join the reorg-coverage universe", - "Rollback coverage guard @regression swq_source_cap_activation.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", - "Rollback coverage guard @regression tableLifecycle.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", - "Rollback coverage guard @regression the replica calls the COINPay re-derive, and never on a truncated replica", - "Rollback coverage guard @regression updated_rows carries the BET status flips keyed by their stamp columns", - "Rollback coverage guard @regression updated_rows carries the DELEGATE v1 rotation rewrite keyed by the rotations journal window", - "Rollback coverage guard @regression updated_rows carries the VOTE poll finalization flip keyed by resolved_block", - "Rollback coverage guard @regression updated_rows carries the cooldown-maturity status_id flip keyed by cooldown_end_block", - "Rollback coverage guard @regression utf8mb4Columns.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", - "dispensers convergence wording does not drift back ../../src/ClientRollback.js does not restate the superseded dispensers convergence channel", - "dispensers convergence wording does not drift back ../../src/SnapshotBuilder.js does not restate the superseded dispensers convergence channel", - "dispensers convergence wording does not drift back ../../src/replicatedTables.js does not restate the superseded dispensers convergence channel", - "dispensers convergence wording does not drift back ../../src/tableLifecycle.js does not restate the superseded dispensers convergence channel", - "dispensers convergence wording does not drift back ./rollback-coverage.test.js does not restate the superseded dispensers convergence channel", - "dispensers convergence wording does not drift back the decoderTxScopedTables comment names the reconcile channel" + "7d990c7da364fa60": [ + "HubClient constructor: array form defaults a non-numeric port to 10000", + "HubClient constructor: array form honors https via the legacy port arg", + "HubClient constructor: array form uses an explicit endpoint array verbatim" ], - "822af834cce5f18d": [ - "ClientSync _bootstrapFromHeight VERIFY_RECOMPUTE: recomputes the terminal block and HALTS on mismatch", - "ClientSync _bootstrapFromHeight clamps base to 0 when depth exceeds the tip", - "ClientSync _bootstrapFromHeight re-pages lookups AFTER applying the block window (closes the T1= 10 blocks advanced", - "ClientSync: heartbeat _scheduleHeartbeat flushes immediately when _hbLastSentBlock is null", - "ClientSync: heartbeat _sendRestHeartbeat does NOT send the inbound SYNC_API_KEY upstream", - "ClientSync: heartbeat _sendRestHeartbeat omits Authorization header when no upstream key", - "ClientSync: heartbeat _sendRestHeartbeat posts to correct URL with Bearer header when the upstream key is set", - "ClientSync: heartbeat _upstreamHeaders carries the upstream key to snapshot reads, not just heartbeats", - "ClientSync: indexer head-fork re-delivery decoder head-fork behaviour is unchanged (block_hash mismatch still triggers catch-up) @regression", - "ClientSync: indexer head-fork re-delivery indexer: at-tip re-delivery with IDENTICAL hashes is a silent skip (true duplicate) @regression", - "ClientSync: indexer head-fork re-delivery indexer: at-tip re-delivery with a DIFFERENT hash triggers catch-up (lost 1-block reorg) @regression", - "ClientSync: misc branch coverage _flushHeartbeat: swallows ws.send error", - "ClientSync: misc branch coverage _haltOnDivergence: logs on recordHalt failure but still halts in memory", - "ClientSync: misc branch coverage _haltOnDivergence: uses defaults when mismatches/sources are falsy", - "ClientSync: misc branch coverage _safeParse: returns raw string when JSON.parse fails", - "ClientSync: misc branch coverage _verifyRecompute: returns null for decoder dbType", - "ClientSync: misc branch coverage _verifyTableCounts: treats NaN local count as 0", - "ClientSync: misc branch coverage clearHalt: logs error when db.clearHalt throws", - "ClientSync: misc branch coverage clearHalt: logs without \"was halted\" when _halted is null", - "ClientSync: misc branch coverage constructor: validatorId falls back to \"unknown\" when hostname() is empty", - "ClientSync: oversized catch-up fallback routes by truncation full-history replica: size error still routes to _bootstrapFromSnapshot (unchanged) @regression", - "ClientSync: oversized catch-up fallback routes by truncation truncated replica: size error routes to _bootstrapFromHeightRetry, NOT the full snapshot @regression", - "ClientSync: small branches _applyBlockEvent sets lastHashes to {block_hash} for decoder dbType", - "ClientSync: small branches _applyBlockEvent: state-commitment roots withheld at an active height HALTS when only block_merkle_root is withheld (a correct balances_root is not a pass)", - "ClientSync: small branches _applyBlockEvent: state-commitment roots withheld at an active height HALTS with state-commitment-missing when the source omits balances_root", - "ClientSync: small branches _applyBlockEvent: state-commitment roots withheld at an active height a state-hash read failure then redelivery still compares the commitment roots", - "ClientSync: small branches _applyBlockEvent: state-commitment roots withheld at an active height clears the carried roots once every gate passes, so a later duplicate stays a skip", - "ClientSync: small branches _applyBlockEvent: state-commitment roots withheld at an active height does NOT halt on a null state_root: ServerPoller nulls it for catch-up-burst blocks", - "ClientSync: small branches _applyBlockEvent: state-commitment roots withheld at an active height does NOT halt when the replica itself says the commitment is not active", - "ClientSync: small branches _applyBlockEvent: state-commitment roots withheld at an active height still halts with state-commitment-divergence on a root MISMATCH", - "ClientSync: small branches _handleBlock (decoder): logs gap and triggers catch-up when blockIndex > lastApplied+1", - "ClientSync: small branches _handleBlock: HALT_ON_DIVERGENCE=true calls _haltOnDivergence on hash mismatch", - "ClientSync: small branches _handleBlock: STRICT mode rejects on timeout and records the strict block (M-22)", - "ClientSync: small branches _handleReorg: a legitimate below-tip reorg still rolls back and moves the cursor", - "ClientSync: small branches _handleReorg: decoder track also HALTS on max-depth exceed", - "ClientSync: small branches _handleReorg: exceeds MAX_ROLLBACK_DEPTH \u2192 HALTS and does NOT rollback", - "ClientSync: small branches _handleReorg: target ABOVE the tip is ignored (no rollback, no cursor advance)", + "7e0925801ccae7f1": [ + "Integration: REST API GET /snapshot/:dbType/:chain/:network returns 404 when no blocks", + "Integration: REST API GET /snapshot/:dbType/:chain/:network returns gzip-compressed full snapshot" + ], + "7e7da713c509ab55": [ + "E2E: Full Lifecycle 1.1 Cold bootstrap from snapshot bootstraps replica from server snapshot with correct data", + "E2E: Full Lifecycle 1.2 Live sync after bootstrap receives new blocks via WebSocket after bootstrap", + "E2E: Full Lifecycle 1.3 Sustained live sync syncs 50 blocks inserted incrementally", + "E2E: Full Lifecycle 1.4 Idle period (no new data) remains stable with no new blocks", + "E2E: Full Lifecycle 1.5 Resume after idle syncs new blocks after an idle period" + ], + "8018794f66fac00f": [ "ClientSync: stop() clears _hbTimer, closes all ws connections, empties wsConns", - "ClientSync: stop() tolerates missing _hbTimer", - "ClientSync: strict cross-source gate survives catch-up (M-22) _incrementalCatchUp refuses to run single-source while a strict block is pending", - "ClientSync: strict cross-source gate survives catch-up (M-22) a second source confirming the block clears the strict block and unblocks catch-up", - "ClientSync: strict cross-source gate survives catch-up (M-22) a strict cross-source timeout records the block and retains its pending hash", - "ClientSync: strict cross-source gate survives catch-up (M-22) catch-up proceeds normally once no strict block is pending" + "ClientSync: stop() tolerates missing _hbTimer" + ], + "805df1c0d5571b8d": [ + "ClientSync maybeVerifyCompleteness does not sweep once halted on a divergence", + "ClientSync maybeVerifyCompleteness does not sweep while the replica is behind the source", + "ClientSync maybeVerifyCompleteness is inert when the interval is 0", + "ClientSync maybeVerifyCompleteness logs and continues when the source is unreachable", + "ClientSync maybeVerifyCompleteness reports a shortfall against the primary source at equal heights", + "ClientSync maybeVerifyCompleteness throttles to COMPLETENESS_CHECK_INTERVAL" + ], + "80af9bed82bea8f3": [ + "HubClient call multi-endpoint fallback falls back to the next endpoint and stickies the good one", + "HubClient call multi-endpoint fallback returns null and records failures when every endpoint fails" + ], + "81aeefdb52ea39d2": [ + "SnapshotBuilder snapshot concurrency cap cap is per Database instance, floored at 1 for tiny pools", + "SnapshotBuilder snapshot concurrency cap caps incremental snapshots on the same per-Database semaphore", + "SnapshotBuilder snapshot concurrency cap defaults the cap to poolSize - 2 (reserves poller + one short-read conn)", + "SnapshotBuilder snapshot concurrency cap falls back to per-dbType pool sizing, then DB_POOL_SIZE env", + "SnapshotBuilder snapshot concurrency cap honours MAX_CONCURRENT_SNAPSHOTS but clamps to [1, poolSize - 1]", + "SnapshotBuilder snapshot concurrency cap rejects a full snapshot with 503 SNAPSHOT_BUSY once the cap is reached, without opening a read view", + "SnapshotBuilder snapshot concurrency cap releases the slot when the stream throws", + "SnapshotBuilder snapshot concurrency cap tracks slots independently per Database (one chain cannot starve another)" + ], + "81b2c5034f4c92dd": [ + "ClientSync: connectWebSocket close handler: calls scheduleReconnect", + "ClientSync: connectWebSocket connectWebSockets iterates all sources", + "ClientSync: connectWebSocket error handler: logs the error message", + "ClientSync: connectWebSocket message handler: an ordinary handler error does NOT exit the process", + "ClientSync: connectWebSocket message handler: calls handleEvent for a valid block event", + "ClientSync: connectWebSocket message handler: escalates mid-stream bootstrap exhaustion to process.exit(1)", + "ClientSync: connectWebSocket message handler: logs invalid WS event", + "ClientSync: connectWebSocket message handler: logs on malformed JSON", + "ClientSync: connectWebSocket message handler: logs when handleEvent rejects", + "ClientSync: connectWebSocket open handler: logs connected message", + "ClientSync: connectWebSocket scheduleReconnect: no-op when running=false", + "ClientSync: connectWebSocket scheduleReconnect: reconnects after CLIENT_RECONNECT_DELAY when running=true", + "ClientSync: connectWebSocket stores ws in wsConns and registers handlers", + "ClientSync: connectWebSocket triggers scheduleReconnect when WS constructor throws", + "ClientSync: connectWebSocket uses ?sync_mode=infra-only query string when SYNC_MODE env is set" + ], + "82ad4278d662f2a2": [ + "contract_state_root: arming boundary and reorg @regression a snapshot bootstrap at an armed height agrees with a from-genesis node", + "contract_state_root: arming boundary and reorg @regression an orphaned write reverts without any rollback-repair pass" + ], + "82de2fae4693c94d": [ + "Integration: the applier can write every table it replicates accepts a schema-shaped row for every replicated table, with no applier-class error" + ], + "8340f62c3bf4e723": [ + "contract_state_root: frozen row-to-leaf mapping @regression MAX(id) runs over tombstones too: a deleted key stays deleted (the ordering trap)", + "contract_state_root: frozen row-to-leaf mapping @regression a SQL-NULL state_value is the deletion tombstone: no leaf, never a hash of null or \"\"", + "contract_state_root: frozen row-to-leaf mapping @regression a resurrected key comes back with its NEW value, not its pre-delete one", + "contract_state_root: frozen row-to-leaf mapping @regression an ordinary value hashes the RAW STORED STRING, never the JSON.parse form", + "contract_state_root: frozen row-to-leaf mapping @regression state_value = \"\" commits leafHash(\"\") and is distinct from absent", + "contract_state_root: frozen row-to-leaf mapping @regression the tombstone mapping DIFFERS from the block-merkle mapping, deliberately", + "contract_state_root: inertness @regression an INERT chain issues ZERO contract_state queries and offers no candidate", + "contract_state_root: inertness @regression an inert block stores NULL in the extension column, which is what EMPTY means", + "contract_state_root: inertness @regression every GENESIS-armed testnet chain queries from block 0, with no below-arming region", + "contract_state_root: inertness @regression the ARMED chain DOES query and DOES offer a candidate (the gate really opened)", + "contract_state_root: inertness @regression the activation maps hold exactly the armed set, and MAINNET is untouched" ], "83fe31113184d5b3": [ "ClientSync: platform-train activation halt @regression HALTS at the activation height when the build lacks the required rule set, naming the set and the height", @@ -1352,6 +1932,48 @@ "weightless stake-weight rows fail closed twin parity with the indexer guard rejects \"null\"", "weightless stake-weight rows fail closed twin parity with the indexer guard rejects null" ], + "85c74ea535a25390": [ + "E2E: Transparency Log 8.1 Transparency log populated during sync records hashes for all synced blocks", + "E2E: Transparency Log 8.2 Transparency log after reorg removes reorged entries and adds new ones", + "E2E: Transparency Log 8.3 Transparency log pagination paginates correctly with page and limit params", + "E2E: Transparency Log 8.4 Merkle inclusion proof round-trip proof validates against the root returned by /root/latest", + "E2E: Transparency Log 8.5 Root/latest empty log returns null epoch and merkle_root before any blocks are recorded" + ], + "8602ff4f2d85519c": [ + "SnapshotBuilder streamFullSnapshot client-abort releases the read view and stops when the client disconnects mid-stream" + ], + "8612e91a8417e932": [ + "Chaos: Source Database Resilience CE-SRC-01: Complete Source DB Unavailability baseline: server /status returns 200 before fault injection", + "Chaos: Source Database Resilience CE-SRC-01: Complete Source DB Unavailability data integrity maintained after source DB recovery", + "Chaos: Source Database Resilience CE-SRC-01: Complete Source DB Unavailability server process remains alive while source DB is completely down", + "Chaos: Source Database Resilience CE-SRC-01: Complete Source DB Unavailability server recovers and resumes sync after source DB is restored", + "Chaos: Source Database Resilience CE-SRC-02: Slow Query Responses latency returns to normal after toxic is removed", + "Chaos: Source Database Resilience CE-SRC-02: Slow Query Responses server still advances block height under injected query latency", + "Chaos: Source Database Resilience CE-SRC-03: Connection Pool Exhaustion server recovers after timeout toxic is removed", + "Chaos: Source Database Resilience CE-SRC-03: Connection Pool Exhaustion server stays alive when all DB connections are held for 30s", + "Chaos: Source Database Resilience CE-SRC-04: Intermittent Connection Drops server continues advancing block height under 30% TCP reset rate", + "Chaos: Source Database Resilience CE-SRC-04: Intermittent Connection Drops server remains alive throughout intermittent drops", + "Chaos: Source Database Resilience CE-SRC-04: Intermittent Connection Drops success rate returns to 100% after toxic is removed", + "Chaos: Source Database Resilience CE-SRC-05: Source Down \u2192 Blocks Accumulate \u2192 Recovery full data integrity after source DB outage with accumulated blocks" + ], + "86523982ea831a05": [ + "ClientSync: independent recompute halt @regression HALTS when replicated rows do not hash to the committed block hash", + "ClientSync: independent recompute halt @regression a recompute DB error is logged but does NOT halt (no self-inflicted fork on infra faults)", + "ClientSync: independent recompute halt @regression does NOT halt when rows hash to the committed block hash (clean block advances)", + "ClientSync: independent recompute halt @regression skips recompute when VERIFY_RECOMPUTE is disabled (opt-out for plain replicas)" + ], + "87ba7838842f7cf2": [ + "04 Subscriber Scaling 1 subscriber", + "04 Subscriber Scaling 10 subscribers", + "04 Subscriber Scaling 25 subscribers", + "04 Subscriber Scaling 5 subscribers", + "04 Subscriber Scaling 50 subscribers" + ], + "87e2f6a904c7a19a": [ + "ClientSync verifyRecompute join-block skip full-history replica (null base) recomputes the lowest block too", + "ClientSync verifyRecompute join-block skip skips recompute for the bootstrap join block (no base-1 predecessor)", + "ClientSync verifyRecompute join-block skip still recomputes every block above the join block" + ], "8908175de26042da": [ "pinnedValidators @regression fails closed (null) on a malformed env override", "pinnedValidators @regression is INERT: every real (chain, network) pins null", @@ -1371,6 +1993,21 @@ "pinnedValidators: rotation seed checkpoint @regression parses a well-formed env seed override (case-insensitive lookup)", "pinnedValidators: rotation seed checkpoint @regression returns null for an unknown chain/network and for null args" ], + "890c1afd26223048": [ + "ClientSync: divergence halt @regression a halted client REFUSES to apply blocks", + "ClientSync: divergence halt @regression a prior uncleared halt in sync_halt keeps the client halted on start (no silent resume)", + "ClientSync: divergence halt @regression clearHalt resumes the client and clears the durable record", + "ClientSync: divergence halt @regression clearing a halt-state-check-failed state does not wipe the unread sync_halt row", + "ClientSync: divergence halt @regression haltOnDivergence sets the halt, persists it durably, and clears pending hashes", + "ClientSync: divergence halt @regression is idempotent: a second divergence does not double-record or change the halt block", + "ClientSync: divergence halt @regression re-reads the halt table while idling, so a recovered database is not stalled forever", + "ClientSync: divergence halt @regression starts healthy (not halted)", + "ClientSync: divergence halt @regression stays HALTED (idle, no catch-up) when the start-time halt check throws" + ], + "89f9f90cb8d11db4": [ + "E2E: state_hash fault injection - updated_rows drop -> state-hash-divergence CONTROL: applying the updated_rows flip recomputes an identical state_hash (no halt)", + "E2E: state_hash fault injection - updated_rows drop -> state-hash-divergence FAULT: dropping the updated_rows apply diverges the state_hash and HALTS durably" + ], "8a703039473bdaa7": [ "Boundary: WebSocket Limits backpressure (item 5410: drop only genuinely stalled peers) a fully-drained buffer keeps the peer healthy and clears any stall window", "Boundary: WebSocket Limits backpressure (item 5410: drop only genuinely stalled peers) arms but does not trip the stall window on the first non-draining send", @@ -1453,202 +2090,167 @@ "validation validateWsEvent rejects null", "validation validateWsEvent rejects undefined" ], - "8b6cb617a8c580f3": [ - "ClientSync: checkpoint-quorum anchor @regression HALTS when the checkpoint quorum is INVALID under the pinned set (rogue signer)", - "ClientSync: checkpoint-quorum anchor @regression HALTS when the quorum-signed state_root disagrees with the replica's own recompute", - "ClientSync: checkpoint-quorum anchor @regression REJECTS a checkpoint_seq regression (source rewound / withholding) without anchoring", - "ClientSync: checkpoint-quorum anchor @regression WARNS on a rootless checkpoint at a commitment-ACTIVE height (does not anchor, does not halt)", - "ClientSync: checkpoint-quorum anchor @regression does NOT halt when the quorum verifies and the state_root matches the replica", - "ClientSync: checkpoint-quorum anchor @regression does not warn freshness when the anchor is within CHECKPOINT_FRESHNESS_BLOCKS of the tip", - "ClientSync: checkpoint-quorum anchor @regression fetches the anchor from CHECKPOINT_ANCHOR_URL out-of-band when configured", - "ClientSync: checkpoint-quorum anchor @regression is INERT with no pinned set: no fetch, no halt", - "ClientSync: checkpoint-quorum anchor @regression never halts on a transport error (404 / network)", - "ClientSync: checkpoint-quorum anchor @regression records the verified checkpoint_seq high-water mark on success", - "ClientSync: checkpoint-quorum anchor @regression skips (no halt, no local read) when the replica has not reached the checkpoint height", - "ClientSync: checkpoint-quorum anchor @regression skips a genuinely pre-commitment checkpoint SILENTLY (snapshot below the flag-day)", - "ClientSync: checkpoint-quorum anchor @regression warns (no halt) when the anchor is staler than CHECKPOINT_FRESHNESS_BLOCKS behind the tip", - "ClientSync: checkpoint-quorum rotation following @regression HALTS when a rotated checkpoint is not signed by the authoritative set (forged quorum)", - "ClientSync: checkpoint-quorum rotation following @regression HALTS when a rotated checkpoint's committed state_root disagrees with the recompute", - "ClientSync: checkpoint-quorum rotation following @regression HALTS when the replica's recompute disagrees with the pinned seed (different chain)", - "ClientSync: checkpoint-quorum rotation following @regression does NOT halt (waits) when the rotated set's snapshot is not yet attested", - "ClientSync: checkpoint-quorum rotation following @regression does NOT halt (waits) when the seed height is not yet recomputed locally", - "ClientSync: checkpoint-quorum rotation following @regression does NOT halt on a transport error while fetching the checkpoint range", - "ClientSync: checkpoint-quorum rotation following @regression follows the pinned seed forward to a rotated checkpoint and does NOT halt" + "8c55921529d21bf6": [ + "E2E: Decoder DB Lifecycle Cold bootstrap replica bootstraps from a decoder full snapshot" ], - "8bbb1aab764e0740": [ - "armed map v2: fingerprint module and publication both /health bodies, 503 starting and 200 ready, carry v1 and v2", - "armed map v2: fingerprint module and publication identity pin records v2 and its row count beside v1", - "armed map v2: fingerprint module and publication identity pin reports a moved v2 and a changed row count, and nothing for an identical tree", - "armed map v2: fingerprint module and publication is memoised per process, like v1", - "armed map v2: fingerprint module and publication is the canonical fingerprint of the manifest rows, with no second computation path", - "armed map v2: fingerprint module and publication names each row by the sha256 of its exported value, so a mismatch points at the row", - "armed map v2: fingerprint module and publication never lists a directory, so the value cannot depend on the file layout", - "armed map v2: fingerprint module and publication publishes a 64-hex fingerprint over every manifest row", - "armed map v2: fingerprint module and publication publishes v1 unchanged and v2 after it, in that order" + "8dd046e550af23cc": [ + "BlockBroadcaster addSubscription adds ws to subscribers set", + "BlockBroadcaster addSubscription does not send status if none available", + "BlockBroadcaster addSubscription registers close and error handlers", + "BlockBroadcaster addSubscription rejects when per-IP limit exceeded", + "BlockBroadcaster addSubscription sends initial status if available", + "BlockBroadcaster addSubscription sets metadata on ws", + "BlockBroadcaster addSubscription uses x-forwarded-for when TRUST_PROXY is true" ], - "910a4f5c866b3b8b": [ - "SWQ source-cap follower gate (SWQ-TRUNC-1 liveness) @regression @tier1 SPV forward-follow getStakeWeightsByCapabilityAsOf at/after activation the reconstruction is source-capped too (matches the committed root)", - "SWQ source-cap follower gate (SWQ-TRUNC-1 liveness) @regression @tier1 SPV forward-follow getStakeWeightsByCapabilityAsOf below activation the reconstruction keeps the legacy uncapped LIMIT (unchanged pre-flag-day)", - "SWQ source-cap follower gate (SWQ-TRUNC-1 liveness) @regression @tier1 live getStakeWeightsByCapability an un-collated venue keeps the bare window: the cap and the collation are separate gates", - "SWQ source-cap follower gate (SWQ-TRUNC-1 liveness) @regression @tier1 live getStakeWeightsByCapability at/after activation (BTC:mainnet >= 960000) uses the windowed source-cap", - "SWQ source-cap follower gate (SWQ-TRUNC-1 liveness) @regression @tier1 live getStakeWeightsByCapability below activation (BTC:mainnet < 960000) uses the legacy uncapped LIMIT", - "SWQ source-cap follower gate (SWQ-TRUNC-1 liveness) @regression @tier1 live getStakeWeightsByCapability drops the overflow source above maxSources (follower selects the same set the source commits)", - "SWQ source-cap follower gate (SWQ-TRUNC-1 liveness) @regression @tier1 live getStakeWeightsByCapability stays on the legacy path when no coin/network is threaded (backward compatible)" + "8e78b69ca3426aa3": [ + "state_root reserved sub-trees: gate is inert EXCEPT the armed set @regression the activation maps hold EXACTLY the armed set (arming is a code change, not config)" ], - "9814f122bb680067": [ - "Database constructor: dbType default defaults dbType to \"indexer\" when not provided", - "Database halt methods clearHalt: returns 0 when result is falsy", - "Database halt methods clearHalt: returns affectedRows", - "Database halt methods getActiveHalt: PROPAGATES a transient query error (fail-closed, not a silent [])", - "Database halt methods getActiveHalt: returns null when no rows", - "Database halt methods getActiveHalt: returns the first row when rows present", - "Database halt methods recordHalt: idempotent (returns existing when block_index matches)", - "Database halt methods recordHalt: inserts new halt when existing block_index differs", - "Database halt methods recordHalt: inserts new halt when none active", - "Database halt methods recordHalt: returns null (not a throw) when the post-insert read throws", - "Database halt methods recordHalt: still INSERTs when the idempotency pre-check read throws (durability first)", - "Database halt methods recordHalt: uses default \"divergence\" when reason is null, defaults mismatches/sources to []", - "Database.addMissingColumns(): edge branches reads COLUMN_NAME (uppercase) from information_schema rows", - "Database.addMissingColumns(): edge branches skips (logs error) a column with an invalid identifier name", - "Database.addMissingColumns(): edge branches throws and logs when ALTER TABLE fails", - "Database.addMissingColumns(): edge branches warns and skips a column when extractColumnDefinition returns null", - "Database.beginReadSnapshot() acquires a DEDICATED connection and runs SET / START TRANSACTION on it", - "Database.beginReadSnapshot() does NOT touch the shared transactionConnection (decoupled from the writer)", - "Database.beginReadSnapshot() on query error: releases the dedicated connection and throws (shared field untouched)", - "Database.beginTransaction() acquires a connection and calls beginTransaction on it", - "Database.beginTransaction() if transactionConnection already exists: releases it first, then opens new one", - "Database.beginTransaction() releases conn and nulls transactionConnection when beginTransaction throws", - "Database.close() calls pool.end() and resolves", - "Database.close() swallows a pool.end() error", - "Database.commitReadSnapshot() / rollbackReadSnapshot() both are no-ops on a null connection", - "Database.commitReadSnapshot() / rollbackReadSnapshot() commitReadSnapshot commits then releases the connection", - "Database.commitReadSnapshot() / rollbackReadSnapshot() commitReadSnapshot still releases when commit throws", - "Database.commitReadSnapshot() / rollbackReadSnapshot() rollbackReadSnapshot rolls back then releases the connection", - "Database.commitReadSnapshot() / rollbackReadSnapshot() rollbackReadSnapshot swallows a rollback error but still releases (best-effort)", - "Database.commitTransaction() commits, releases, nulls, returns true on success", - "Database.commitTransaction() on commit error: rolls back, releases, nulls, throws", - "Database.commitTransaction() returns false when no active transactionConnection", - "Database.createDatabase() creates the DB and returns true on success", - "Database.createDatabase() retries once on error then succeeds", - "Database.createDatabase() throws for an invalid dbName without connecting", - "Database.doQuery() coerces plain-object args to string, leaves Buffer intact", - "Database.doQuery() does NOT release conn when inside a transaction", - "Database.doQuery() explicit conn arg: query errors propagate (caller rolls back the snapshot)", - "Database.doQuery() explicit conn arg: runs on that connection, never acquires/releases one", - "Database.doQuery() on query error in non-tx path with opts.rethrow: logs, releases, AND re-throws (fail-closed)", - "Database.doQuery() on query error in non-tx path: logs error, does NOT throw, returns []", - "Database.doQuery() on query error inside a transaction: logs AND re-throws", - "Database.doQuery() returns [] and does NOT call getConnection when query is null", - "Database.doQuery() returns [] when query is undefined", - "Database.doQuery() runs a query via a connection and releases it (non-tx path)", + "8ea1c406c845cec1": [ + "Integration: TestDatabase.getBlockScopedRows reads the lifecycle key scopes a close_block-keyed table (rollcalls) by close_block, not block_index", + "Integration: TestDatabase.getBlockScopedRows reads the lifecycle key still scopes an ordinary block_index-keyed table (transactions) by block_index" + ], + "8f25bc9eed65018d": [ + "Integration: REST API GET /snapshot/:dbType/:chain/:network/since/:blockHeight returns 400 for invalid blockHeight", + "Integration: REST API GET /snapshot/:dbType/:chain/:network/since/:blockHeight returns incremental snapshot" + ], + "90829ca9a8a00309": [ + "SnapshotBuilder SnapshotStreamWriter (backpressure + client-abort) blocks until drain when the buffer is full (write() returns false)", + "SnapshotBuilder SnapshotStreamWriter (backpressure + client-abort) finish() detaches the disconnect handler and ends the stream", + "SnapshotBuilder SnapshotStreamWriter (backpressure + client-abort) rejects (aborted) and destroys gzip when the client disconnects mid-write", + "SnapshotBuilder SnapshotStreamWriter (backpressure + client-abort) resolves immediately when the buffer has room (write() returns true)" + ], + "908f56d4f3992093": [ + "08 Bootstrap Stampede (N-concurrent-bootstrap load) 10 concurrent bootstraps (cohort ceiling) shed the excess with a retryable 503", + "08 Bootstrap Stampede (N-concurrent-bootstrap load) 5 concurrent bootstraps (cohort floor) are all served, poller unaffected", + "08 Bootstrap Stampede (N-concurrent-bootstrap load) a 25-validator flag-day cohort cannot pin the pool", + "08 Bootstrap Stampede (N-concurrent-bootstrap load) derives a cap that always leaves the poller a connection" + ], + "910a4f5c866b3b8b": [ + "SWQ source-cap follower gate (SWQ-TRUNC-1 liveness) @regression @tier1 SPV forward-follow getStakeWeightsByCapabilityAsOf at/after activation the reconstruction is source-capped too (matches the committed root)", + "SWQ source-cap follower gate (SWQ-TRUNC-1 liveness) @regression @tier1 SPV forward-follow getStakeWeightsByCapabilityAsOf below activation the reconstruction keeps the legacy uncapped LIMIT (unchanged pre-flag-day)", + "SWQ source-cap follower gate (SWQ-TRUNC-1 liveness) @regression @tier1 live getStakeWeightsByCapability an un-collated venue keeps the bare window: the cap and the collation are separate gates", + "SWQ source-cap follower gate (SWQ-TRUNC-1 liveness) @regression @tier1 live getStakeWeightsByCapability at/after activation (BTC:mainnet >= 960000) uses the windowed source-cap", + "SWQ source-cap follower gate (SWQ-TRUNC-1 liveness) @regression @tier1 live getStakeWeightsByCapability below activation (BTC:mainnet < 960000) uses the legacy uncapped LIMIT", + "SWQ source-cap follower gate (SWQ-TRUNC-1 liveness) @regression @tier1 live getStakeWeightsByCapability drops the overflow source above maxSources (follower selects the same set the source commits)", + "SWQ source-cap follower gate (SWQ-TRUNC-1 liveness) @regression @tier1 live getStakeWeightsByCapability stays on the legacy path when no coin/network is threaded (backward compatible)" + ], + "932531f1175e9a43": [ + "ClientApplier applyDispensersReplace clears the table even when the new set is empty (decoder)", + "ClientApplier applyDispensersReplace is a no-op on a non-decoder DB", + "ClientApplier applyDispensersReplace replaces atomically: DELETE then INSERT inside one transaction (decoder)", + "ClientApplier applyDispensersReplace rolls back and rethrows if a write fails (decoder, table left intact)" + ], + "93be970735a5f782": [ "Database.ensureReplicaSecondaryIndexes(): anchor_actions bundle-section primary key adds section_index itself and then swaps the key in the same pass", "Database.ensureReplicaSecondaryIndexes(): anchor_actions bundle-section primary key is a no-op when the composite key is already in place (idempotent)", "Database.ensureReplicaSecondaryIndexes(): anchor_actions bundle-section primary key leaves an unexpected primary key alone", "Database.ensureReplicaSecondaryIndexes(): anchor_actions bundle-section primary key leaves the stale key alone when the column ADD is refused", "Database.ensureReplicaSecondaryIndexes(): anchor_actions bundle-section primary key widens a stale single-column PRIMARY KEY to (action_index, section_index)", - "Database.ensureReplicaSecondaryIndexes(): validator_rewards reward_unique qualifier key adds round_qualifier itself and then rebuilds the key in the same pass", - "Database.ensureReplicaSecondaryIndexes(): validator_rewards reward_unique qualifier key does nothing when reward_unique is absent", - "Database.ensureReplicaSecondaryIndexes(): validator_rewards reward_unique qualifier key is a no-op for a decoder replica (indexer-only)", "Database.ensureReplicaSecondaryIndexes(): validator_rewards reward_unique qualifier key is a no-op when the five-column key is already in place (idempotent)", - "Database.ensureReplicaSecondaryIndexes(): validator_rewards reward_unique qualifier key leaves an unexpected reward_unique definition alone", - "Database.ensureReplicaSecondaryIndexes(): validator_rewards reward_unique qualifier key leaves the stale key alone when the column ADD is refused", "Database.ensureReplicaSecondaryIndexes(): validator_rewards reward_unique qualifier key rebuilds a stale four-column reward_unique with round_qualifier appended", "Database.ensureReplicaSecondaryIndexes(): votes append-only migration creates the widened key on a replica missing both (defensive)", + "Database.ensureReplicaSecondaryIndexes(): votes append-only migration is a no-op for a decoder replica (indexer-only)" + ], + "93d6210945bb30dd": [ + "ClientApplier insertRows attest_validator_stats surrogate id (strip-only class) issues no DELETE: the natural key is composite and a scoped delete would drop siblings", + "ClientApplier insertRows attest_validator_stats surrogate id (strip-only class) leaves a row that carries no id alone", + "ClientApplier insertRows attest_validator_stats surrogate id (strip-only class) refuses a row that carries only the stripped id rather than inserting nothing", + "ClientApplier insertRows attest_validator_stats surrogate id (strip-only class) still upserts on the natural key, so a re-dump refreshes the counters", + "ClientApplier insertRows attest_validator_stats surrogate id (strip-only class) strips the source id so the replica keeps its own", + "ClientApplier insertRows backtick-wraps column names", + "ClientApplier insertRows batches inserts in groups of 100", + "ClientApplier insertRows blocks surrogate id (item 808) deletes the existing row for that block_index first, so a re-send is idempotent", + "ClientApplier insertRows blocks surrogate id (item 808) does not use IGNORE or UPSERT, which would drop or overwrite a block", + "ClientApplier insertRows blocks surrogate id (item 808) fails closed on a row with no block_index rather than appending a duplicate", + "ClientApplier insertRows blocks surrogate id (item 808) leaves a legacy row that carries no id untouched", + "ClientApplier insertRows blocks surrogate id (item 808) scopes the delete to the applied blocks only, never the whole table", + "ClientApplier insertRows blocks surrogate id (item 808) strips the source id so the replica assigns its own", + "ClientApplier insertRows does nothing for empty rows", + "ClientApplier insertRows does nothing for null rows", + "ClientApplier insertRows handles null column values", + "ClientApplier insertRows handles undefined column values as null", + "ClientApplier insertRows keeps refreshing markets.id, whose id space is source-assigned end to end", + "ClientApplier insertRows throws on an invalid column name without querying (fail closed)", + "ClientApplier insertRows throws on an invalid table name without querying (fail closed)", + "ClientApplier insertRows upserts attest_validator_stats with ON DUPLICATE KEY UPDATE covering every carried column", + "ClientApplier insertRows upserts markets with ON DUPLICATE KEY UPDATE covering every carried column", + "ClientApplier insertRows uses INSERT IGNORE for append-only merkle_epochs", + "ClientApplier insertRows uses INSERT IGNORE for index tables", + "ClientApplier insertRows uses INSERT IGNORE for the re-deliverable rollcall_absences", + "ClientApplier insertRows uses INSERT IGNORE for the re-deliverable rollcalls", + "ClientApplier insertRows uses INSERT for non-index tables" + ], + "971aa02f9a73a797": [ + "Integration: TransparencyLog getPage includes logged_at timestamp", + "Integration: TransparencyLog getPage paginates correctly with offset", + "Integration: TransparencyLog getPage returns empty results for page beyond data", + "Integration: TransparencyLog getPage returns paginated results with correct total", + "Integration: TransparencyLog getPage returns results ordered by block_index DESC", + "Integration: TransparencyLog recordBlock ignores duplicate block_index (INSERT IGNORE)", + "Integration: TransparencyLog recordBlock inserts a row into sync_meta", + "Integration: TransparencyLog recordBlock records multiple blocks", + "Integration: TransparencyLog rollback cleanup preserves entries before rollback point after manual delete" + ], + "9743546a34b05c9f": [ + "ClientRollback pair-scoped markets rollback (IDX-2 mirror) aborts (fail-closed) on a transient error in the pair-scoped sweep", + "ClientRollback pair-scoped markets rollback (IDX-2 mirror) collects the affected pairs BEFORE the action-scoped delete removes them", + "ClientRollback pair-scoped markets rollback (IDX-2 mirror) deletes a market whose pair kept no surviving order or match", + "ClientRollback pair-scoped markets rollback (IDX-2 mirror) keeps the market when a surviving order still references the pair", + "ClientRollback pair-scoped markets rollback (IDX-2 mirror) keeps the market when only an order_match survives", + "ClientRollback pair-scoped markets rollback (IDX-2 mirror) skips the sweep on a truncated replica", + "ClientRollback pair-scoped markets rollback (IDX-2 mirror) swallows a schema gap in the pair-scoped sweep" + ], + "982b7874b134e4c3": [ + "HubClient getallconfigs watermark regression discards the cache and re-fetches full when the same endpoint serves a lower watermark", + "HubClient getallconfigs watermark regression does not treat a regressed-but-unwrapped (no seq/configs) payload as a regression" + ], + "987a7188bf95b1e7": [ + "SyncService scheduleHubRepoll logs (does not throw) when a re-poll fails", + "SyncService scheduleHubRepoll re-discovers chains on each interval tick and logs new chains", + "SyncService scheduleHubRepoll sets up an interval" + ], + "98e33e68315706b4": [ "Database.ensureReplicaSecondaryIndexes(): votes append-only migration drops the stale poll_voter_choice and creates the widened unique key", - "Database.ensureReplicaSecondaryIndexes(): votes append-only migration is a no-op for a decoder replica (indexer-only)", "Database.ensureReplicaSecondaryIndexes(): votes append-only migration is a no-op when the widened key already exists (idempotent)", - "Database.ensureReplicatedColumns() adds missing columns for indexer dbType", - "Database.ensureReplicatedColumns() returns immediately for decoder dbType (no-op)", - "Database.ensureReplicatedColumns() skips column when column already exists on replica", - "Database.ensureReplicatedColumns() skips column when table does not exist on replica", - "Database.getActionScopedRows() queries with action/transaction join", - "Database.getActions() returns rows from actions table", - "Database.getBlockHashRow() PROPAGATES a query error with opts.rethrow (fail-closed duplicate guard)", - "Database.getBlockHashRow() decoder: returns null when no rows", - "Database.getBlockHashRow() decoder: returns row with block_hash only", - "Database.getBlockHashRow() indexer: returns null when no rows", - "Database.getBlockHashRow() indexer: returns row with ledger/actions/contract hashes", - "Database.getBlockHashRow() swallows a query error and returns null by default (fail-soft preserved)", - "Database.getBlockRows() decoder: uses block_hash column", - "Database.getBlockRows() indexer: uses ledger/actions/contract hash columns", - "Database.getBlockScopedRows() leaves every other block-scoped table on block_index", - "Database.getBlockScopedRows() queries the given table by block_index", - "Database.getBlockScopedRows() scopes a close_block-keyed table by close_block, not the class default", - "Database.getConnection(): circuit breaker circuit open + cooldown expired \u2192 transitions to half-open, succeeds", - "Database.getConnection(): circuit breaker circuit open + cooldown not expired \u2192 throws immediately", - "Database.getConnection(): circuit breaker half-open \u2192 success \u2192 closes circuit", - "Database.getConnection(): circuit breaker happy path: returns connection and resets failures", - "Database.getConnection(): circuit breaker maxAttempts exhaustion: throws when failures < threshold", - "Database.getConnection(): circuit breaker retry-with-backoff: fails once then succeeds", - "Database.getConnection(): circuit breaker returns transactionConnection directly when one is active", - "Database.getConnection(): circuit breaker threshold exceeded: circuit opens and throws", - "Database.getDatabaseStats() returns rows from information_schema query", - "Database.getEmissionRowsForBlock() joins through contract_executions on execution_index (includes NULL action_index rows)", - "Database.getEmissionRowsForBlock() selects only the four protocol columns, never em.* (would carry the id PK)", - "Database.getFirstActionIndex() PROPAGATES a query error with opts.rethrow (fail-closed rollback gate)", - "Database.getFirstActionIndex() returns Number when found", - "Database.getFirstActionIndex() returns null when no rows", - "Database.getFirstActionIndex() swallows a query error and returns null by default (fail-soft preserved)", - "Database.getLastBlock() PROPAGATES a query error with opts.rethrow (fail-closed resume cursor)", - "Database.getLastBlock() returns Number when rows contain a block_index", - "Database.getLastBlock() returns null when row.block_index is null", - "Database.getLastBlock() returns null when rows is empty", - "Database.getLastBlock() swallows a query error and returns null by default (fail-soft preserved)", - "Database.getNonEmptyActionScopedTables() drops candidates the source schema does not have (one missing table fails the whole UNION)", - "Database.getNonEmptyActionScopedTables() issues no query at all when no candidate exists", - "Database.getNonEmptyActionScopedTables() probes every existing candidate in ONE round-trip, with getActionScopedRows' predicate", - "Database.getNonEmptyActionScopedTables() refuses an unsafe table identifier before it reaches the query string", - "Database.getReplicaStatus() falls back to the pre-10.5 SLAVE spelling", - "Database.getReplicaStatus() reads a healthy replica row", - "Database.getReplicaStatus() reports a stopped SQL thread as running:false with NULL, never 0 behind", - "Database.getReplicaStatus() reports not-a-replica on an empty result set (primary / co-located source)", - "Database.getReplicaStatus() returns an unknown result when the grant is missing, never a healthy one", - "Database.getTableCount() propagates the database error with errno intact when the table is absent", - "Database.getTableCount() returns count as Number", - "Database.getTransactions() returns rows from transactions table", - "Database.getTxScopedRows() queries with tx join", - "Database.listExistingTables() THROWS rather than reporting an empty schema when the listing fails", - "Database.listExistingTables() reports a table the caller should skip", - "Database.listExistingTables() returns the table names as a Set, tolerating either column case", - "Database.releaseConnection() is a no-op when transactionConnection is null", - "Database.releaseConnection() releases and nulls transactionConnection when present", - "Database.replicateSchema() calls addMissingColumns for already-existing tables", - "Database.replicateSchema() creates a missing table and calls ensureReplicatedColumns", - "Database.replicateSchema() handles CREATE TABLE throw (deferred) and executes retry block", - "Database.replicateSchema() handles TABLE_NAME (uppercase) keys from information_schema rows", "Database.replicateSchema() retry block: handles TABLE_NAME uppercase keys in retrySet and source rows", - "Database.replicateSchema() retry block: skips invalid table name", "Database.replicateSchema() retry block: skips table when Create Table key is missing (retry createSql null)", "Database.replicateSchema() retry block: skips table when SHOW CREATE TABLE returns empty (retry ddlRows empty)", "Database.replicateSchema() retry block: successfully creates a deferred table (covers the success log)", - "Database.replicateSchema() skips DDL that fails validateDdl (invalid DDL)", - "Database.replicateSchema() skips invalid table name (validateIdentifier fail)", - "Database.replicateSchema() skips table when SHOW CREATE TABLE returns empty rows", - "Database.replicateSchema() skips table when SHOW CREATE TABLE row has no Create Table key", - "Database.rollbackTransaction() is a no-op when no active transaction", - "Database.rollbackTransaction() releases in finally even when rollback throws", - "Database.rollbackTransaction() rolls back and releases when transactionConnection is active", - "Database.streamTableRows() runs ONE un-paged ordered query on the given snapshot connection", - "Database.truncateTable() calls doQuery with TRUNCATE TABLE", - "Database.verifyDatabase() retries once on error then succeeds", - "Database.verifyDatabase() returns false when DB is not found", - "Database.verifyDatabase() returns true when DB exists", - "Database.verifyDatabaseOnce() ends connection in finally even when query throws", - "Database.verifyDatabaseOnce() returns false when DB not found, still ends connection", - "Database.verifyDatabaseOnce() returns true when DB exists and always ends the connection", - "Database.verifyDatabaseOnce() throws (no retry) when createConnection rejects", - "Database.verifySyncTables() _createTableFromFile: executes all statements from file", - "Database.verifySyncTables() creates table when it does not exist (calls _createTableFromFile)", - "Database.verifySyncTables() decoder dbType: creates ONLY sync_halt (transparency log is indexer-only)", - "Database.verifySyncTables() does not create table when it already exists", - "Database.verifySyncTables() indexer dbType: applies the full sync-owned set including sync_halt", - "Database.verifySyncTables() skips non-.sql files", - "Database.verifySyncTables() throws (via util.throwError) when query fails", "Database: table identifier guard allows a normal table name through to the query", "Database: table identifier guard getTableCount rejects an unsafe identifier before querying", "Database: table identifier guard streamTableRows rejects an unsafe identifier before querying", "Database: table identifier guard truncateTable rejects an unsafe identifier before querying" ], + "9922e46bb18b4e81": [ + "Chaos: Replica Database Resilience CE-DST-01: Complete Replica DB Unavailability baseline: replica has blocks 1-10 before fault injection", + "Chaos: Replica Database Resilience CE-DST-01: Complete Replica DB Unavailability client process stays alive while replica DB is down", + "Chaos: Replica Database Resilience CE-DST-01: Complete Replica DB Unavailability client recovers and catches up after replica DB is restored", + "Chaos: Replica Database Resilience CE-DST-01: Complete Replica DB Unavailability no data corruption after replica DB recovery", + "Chaos: Replica Database Resilience CE-DST-02: Slow Write Responses blocks still applied under 2s write latency", + "Chaos: Replica Database Resilience CE-DST-02: Slow Write Responses write performance returns to normal after toxic removal", + "Chaos: Replica Database Resilience CE-DST-03: Connection Pool Exhaustion client recovers after timeout toxic is removed", + "Chaos: Replica Database Resilience CE-DST-03: Connection Pool Exhaustion client stays alive when replica DB connections are held for 30s", + "Chaos: Replica Database Resilience CE-DST-04: Intermittent Connection Drops all blocks eventually reach replica after toxic removal", + "Chaos: Replica Database Resilience CE-DST-04: Intermittent Connection Drops majority of blocks eventually applied under 30% TCP reset rate", + "Chaos: Replica Database Resilience CE-DST-05: Replica Down \u2192 Blocks Accumulate \u2192 Recovery full data integrity after replica outage with accumulated blocks" + ], + "99d874997e2b72e1": [ + "ClientSync applyBlockEvent calls applier.applyBlock", + "ClientSync applyBlockEvent cleans up old pendingHashes entries", + "ClientSync applyBlockEvent handles apply error gracefully", + "ClientSync applyBlockEvent re-applies the source schema when the apply hits a missing table", + "ClientSync applyBlockEvent updates lastAppliedBlock and lastHashes" + ], + "9b652f1a15749f6a": [ + "07 Rollback Performance data integrity after deep rollback", + "07 Rollback Performance rollback 1 block", + "07 Rollback Performance rollback 10 blocks", + "07 Rollback Performance rollback 100 blocks (MAX_ROLLBACK_DEPTH)", + "07 Rollback Performance rollback 25 blocks", + "07 Rollback Performance rollback 5 blocks", + "07 Rollback Performance rollback 50 blocks", + "07 Rollback Performance rollback time scales sub-quadratically with depth" + ], "9c0fc1385ec3e33c": [ "Boundary: Transparency Log Pagination limit parameter limit=\"abc\": defaults to 100", "Boundary: Transparency Log Pagination limit parameter limit=-1: clamped to 1", @@ -1671,109 +2273,22 @@ "Boundary: Transparency Log Pagination page parameter page=999999: no upper clamp, valid high page", "Boundary: Transparency Log Pagination page parameter page=undefined: defaults to 0" ], - "9cd5c17223db456a": [ - "ClientSync _applyBlockEvent calls applier.applyBlock", - "ClientSync _applyBlockEvent cleans up old pendingHashes entries", - "ClientSync _applyBlockEvent handles apply error gracefully", - "ClientSync _applyBlockEvent re-applies the source schema when the apply hits a missing table", - "ClientSync _applyBlockEvent updates lastAppliedBlock and lastHashes", - "ClientSync _handleBlock cross-source verification applies block when two sources match", - "ClientSync _handleBlock cross-source verification applies from primary after timeout when only one source responds", - "ClientSync _handleBlock cross-source verification arms a timeout when only the non-primary source arrives first", - "ClientSync _handleBlock cross-source verification does not apply block when sources have mismatched hashes", - "ClientSync _handleBlock cross-source verification does not double-arm the timer when both sources arrive before expiry", - "ClientSync _handleBlock decoder fork guard does not false-trigger before any block_hash is stored (fresh boot)", - "ClientSync _handleBlock decoder fork guard does not trigger catch-up when the head block re-arrives with the same hash", - "ClientSync _handleBlock decoder fork guard rewinds the orphaned head and catches up from the forked height", - "ClientSync _handleBlock single source mode applies block immediately without waiting", - "ClientSync _handleBlock skips blocks already applied", - "ClientSync _handleBlock triggers catch-up on chain continuity failure", - "ClientSync _handleBlock verification disabled applies block immediately", - "ClientSync _handleBlock verifies chain continuity", - "ClientSync _handleEvent detects gap on status event and triggers catch-up", - "ClientSync _handleEvent does not trigger catch-up when lastAppliedBlock is null", - "ClientSync _handleEvent does not trigger catch-up when no gap", - "ClientSync _handleEvent routes block events to _handleBlock", - "ClientSync _handleEvent routes reorg events to _handleReorg", - "ClientSync _handleEvent runs the completeness sweep against the source that sent the status tick @regression", - "ClientSync _handleEvent upstream replication evidence is unknown, not fresh, before any status event", - "ClientSync _handleEvent upstream replication evidence keeps the source height, staleness verdict and lag from a status event", - "ClientSync _handleEvent upstream replication evidence re-reads the verdict on a status tick that does not advance the height", - "ClientSync _handleEvent upstream replication evidence reads a server older than the fields as unknown rather than fresh", - "ClientSync _handleEvent upstream replication evidence takes the worst verdict across sources and ignores an evicted one", - "ClientSync _handleReorg calls rollback with the event block_index", - "ClientSync _handleReorg handles rollback error gracefully", - "ClientSync _handleReorg loads new lastHashes from DB", - "ClientSync _handleReorg null tip: ignores the reorg entirely (no rollback, no cursor advance)", - "ClientSync _handleReorg resets lastAppliedBlock to block_index - 1", - "ClientSync _handleReorg sets lastHashes to null when rolling back to block 0", - "ClientSync _healSchemaIfStale debounces to one heal per minute", - "ClientSync _healSchemaIfStale heals on missing table (1146) and missing column (1054)", - "ClientSync _healSchemaIfStale ignores non-schema errors and null errors", - "ClientSync _logGap throttling logs the first occurrence immediately", - "ClientSync _logGap throttling resets the suppressed count after emitting a summary", - "ClientSync _logGap throttling suppresses repeats within the window, then emits one summary with the count", - "ClientSync _maybeVerifyCompleteness does not sweep once halted on a divergence", - "ClientSync _maybeVerifyCompleteness does not sweep while the replica is behind the source", - "ClientSync _maybeVerifyCompleteness is inert when the interval is 0", - "ClientSync _maybeVerifyCompleteness logs and continues when the source is unreachable", - "ClientSync _maybeVerifyCompleteness reports a shortfall against the primary source at equal heights", - "ClientSync _maybeVerifyCompleteness throttles to COMPLETENESS_CHECK_INTERVAL", - "ClientSync _runIncrementalCatchUp schema self-heal does not retry when the retry would hit the heal debounce", - "ClientSync _runIncrementalCatchUp schema self-heal heals and retries ONCE when the catch-up apply hits a missing table", - "ClientSync _verifyTableCounts (replica-completeness) at the same height, reports a replica-AHEAD delta on exact-parity tables as reason replica-ahead", - "ClientSync _verifyTableCounts (replica-completeness) does not fault the completeness check when the schema heal itself throws", - "ClientSync _verifyTableCounts (replica-completeness) flags a table the source has rows in but the follower has zeroed", - "ClientSync _verifyTableCounts (replica-completeness) heals the schema when a replicated table is missing locally (errno 1146)", - "ClientSync _verifyTableCounts (replica-completeness) replica-ahead is gated on equal heights and on the registry exact-parity class", - "ClientSync _verifyTableCounts (replica-completeness) reports a table missing entirely from the follower as a full shortfall", - "ClientSync _verifyTableCounts (replica-completeness) returns no mismatches when the follower is complete (local >= source)", - "ClientSync _verifyTableCounts (replica-completeness) skips a malicious table name without passing it to getTableCount", - "ClientSync _verifyTableCounts (replica-completeness) treats absent/invalid table_counts as nothing to check (older source builds)", - "ClientSync _warnTrustPosture does not warn about single-source with 2+ sources", - "ClientSync _warnTrustPosture indexer with 2+ sources emits no SINGLE-SOURCE warning, but DOES warn the checkpoint anchor is off", - "ClientSync _warnTrustPosture indexer with the checkpoint anchor active and a pinned set emits no trust warnings", - "ClientSync _warnTrustPosture warns that the decoder path has no hash rejection", - "ClientSync _warnTrustPosture warns when running single-source (no cross-source rejection)", - "ClientSync bootstrap-failure gating (empty-replica defect) _bootstrapFromSnapshot rejects with BootstrapExhaustedError once all retry rounds exhaust", - "ClientSync bootstrap-failure gating (empty-replica defect) _handleBlock refuses to apply a non-genesis block onto an empty replica", - "ClientSync bootstrap-failure gating (empty-replica defect) start() propagates a permanent bootstrap failure without live-following", - "ClientSync bootstrap-failure gating (empty-replica defect) start() refuses live-follow when bootstrap leaves the replica empty", - "ClientSync constructor handles empty SYNC_SOURCES", - "ClientSync constructor parses SYNC_SOURCES into array", - "ClientSync constructor trims whitespace from sources", + "9cca6fcd72577c24": [ + "ServerPoller buildBlockPayload collects both decoder blocks hash ids under the shared *_hash_id rule @regression", + "ServerPoller buildBlockPayload fails closed on a TRANSIENT updated_rows collection error (deadlock 1213) so the block is retried, not broadcast without updated_rows @regression", + "ServerPoller buildBlockPayload streams the blocks.state_hash_id index_transactions row with the live block @regression" + ], + "9e08b97fcd02776a": [ "ClientSync constructor: SYNC_MODE_=infra-only vs the halting verification gates constructs in infra-only when all three gates are explicitly false, and carries the mode to the subscribe URL", "ClientSync constructor: SYNC_MODE_=infra-only vs the halting verification gates full mode (default) never consults the gates; a decoder replica ignores infra-only (no infra tables)", "ClientSync constructor: SYNC_MODE_=infra-only vs the halting verification gates names only the gates still on", - "ClientSync constructor: SYNC_MODE_=infra-only vs the halting verification gates throws at construction when infra-only is combined with default-on gates (indexer), naming them", - "ClientSync decoder bootstrap completeness _bootstrapFromSnapshot wiring does not run the decoder check in single-source mode", - "ClientSync decoder bootstrap completeness _bootstrapFromSnapshot wiring runs the decoder completeness check even when VERIFY_HASHES is false", - "ClientSync decoder bootstrap completeness _bootstrapFromSnapshot wiring takes the indexer hash path (not the decoder check) for indexer dbType", - "ClientSync decoder bootstrap completeness _verifyDecoderCompleteness flags a truncated snapshot loudly when the source has more rows", - "ClientSync decoder bootstrap completeness _verifyDecoderCompleteness is a no-op for non-decoder dbType", - "ClientSync decoder bootstrap completeness _verifyDecoderCompleteness passes quietly when the follower is complete", - "ClientSync isSourceHeightStale reports stale once the window elapses with no new event", - "ClientSync isSourceHeightStale returns false immediately after an event", - "ClientSync isSourceHeightStale returns null before any WS event is seen", - "ClientSync isSourceHeightStale stays fresh within the staleness window", - "ClientSync persistent replica gaps ages decoder shortfalls from the periodic path only", - "ClientSync persistent replica gaps does not clear a tracked gap on a sweep that never completed", - "ClientSync persistent replica gaps does not escalate a shortfall seen on a single sweep", - "ClientSync persistent replica gaps escalates a shortfall that survives consecutive equal-height sweeps", - "ClientSync persistent replica gaps rate-limits the alert but re-raises immediately when the gap grows", - "ClientSync persistent replica gaps records the persistent gap durably and clears it when the gap closes", - "ClientSync persistent replica gaps reports that the client self-repair pass failed to close a short lookup", - "ClientSync start bootstraps from a full snapshot when the replica is empty", - "ClientSync start does NOT reconcile schema on the empty-replica bootstrap path (bootstrap fetches it itself)", - "ClientSync start passes lastAppliedBlock + 1 to incremental catch-up when resuming a populated replica", - "ClientSync start reconciles the source schema on resume, BEFORE catch-up (creates zero-row tables added post-bootstrap)", - "ClientSync stop sets running to false", - "ClientSync._shouldReconcileDispensers (decoder resume cadence) does not force a reconcile on the first cycle when bootstrap already reconciled", - "ClientSync._shouldReconcileDispensers (decoder resume cadence) reconciles every Nth catch-up in steady state", - "ClientSync._shouldReconcileDispensers (decoder resume cadence) reconciles on the first cycle after a resume that skipped bootstrap", - "ClientSync._shouldReconcileDispensers (decoder resume cadence) reconciles when the last reconcile is older than the max interval", - "ClientSync._shouldReconcileDispensers (decoder resume cadence) skips reconcile within the interval and off the periodic cycle", - "ClientSync._shouldReconcileDispensers (decoder resume cadence) treats a max interval of 0 as disabling the time trigger" + "ClientSync constructor: SYNC_MODE_=infra-only vs the halting verification gates throws at construction when infra-only is combined with default-on gates (indexer), naming them" + ], + "9e1eab683f917093": [ + "ServerPoller seedReorgGuardHash (durable reorg-guard seed) @regression decoder (no transparency log) seeds from the live source read", + "ServerPoller seedReorgGuardHash (durable reorg-guard seed) @regression detects a during-downtime reorg on the first poll after restart", + "ServerPoller seedReorgGuardHash (durable reorg-guard seed) @regression falls back to the live read for a fresh node (no recorded hash) and null cursor", + "ServerPoller seedReorgGuardHash (durable reorg-guard seed) @regression indexer seeds from the recorded (pre-reorg) hash, NOT a live source read" ], "9e46fbfae5839c05": [ "Database.ensureReplicaUtf8mb4Columns does not run on a decoder replica (none of these tables exist there)", @@ -1784,6 +2299,13 @@ "Database.ensureReplicaUtf8mb4Columns widens every narrow column, one ALTER per table, with the twin module's exact clause", "Database.ensureReplicaUtf8mb4Columns widens only the columns the replica actually has, leaving the rest of the ALTER intact" ], + "9f32bf1a82b5f6ab": [ + "ClientSync warnTrustPosture does not warn about single-source with 2+ sources", + "ClientSync warnTrustPosture indexer with 2+ sources emits no SINGLE-SOURCE warning, but DOES warn the checkpoint anchor is off", + "ClientSync warnTrustPosture indexer with the checkpoint anchor active and a pinned set emits no trust warnings", + "ClientSync warnTrustPosture warns that the decoder path has no hash rejection", + "ClientSync warnTrustPosture warns when running single-source (no cross-source rejection)" + ], "a0553a057c488031": [ "replicated-DDL migrations cannot land without a SCHEMA_VERSION bump @regression the gate detects what it claims to detect does not flag DDL on a table this dbType never ships", "replicated-DDL migrations cannot land without a SCHEMA_VERSION bump @regression the gate detects what it claims to detect does not flag DDL quoted inside the migration prose", @@ -1806,6 +2328,67 @@ "collectDerivedAnchorRewards selects by the derive_block_index window with the backdated-only guard", "collectDerivedAnchorRewards swallows ONLY a schema gap (1054/1146); a transient fault propagates so the block is retried" ], + "a1c61939d5e79b8d": [ + "Integration: Client Bootstrap full bootstrap from snapshot preserves exact data values (no type coercion)", + "Integration: Client Bootstrap full bootstrap from snapshot replicates all block data to replica", + "Integration: Client Bootstrap full bootstrap from snapshot replicates index tables correctly", + "Integration: Client Bootstrap incremental catch-up applies only new blocks", + "Integration: Client Bootstrap startup catch-up (start) resumes a pre-populated replica without re-inserting applied rows" + ], + "a2343508ab4cdd95": [ + "state_root reserved sub-trees: gate is inert EXCEPT the armed set @regression MAINNET IS UNARMED for every slot, at every height (the launch guard)", + "state_root reserved sub-trees: gate is inert EXCEPT the armed set @regression all three testnet chains arm contract_state_root from GENESIS", + "state_root reserved sub-trees: gate is inert EXCEPT the armed set @regression exactly the armed set is armed, and nothing else on any chain or height", + "state_root reserved sub-trees: gate is inert EXCEPT the armed set @regression stateRootVersion reports 1 everywhere EXCEPT at and above an armed height", + "state_root reserved sub-trees: gate is inert EXCEPT the armed set @regression the armed height is a real boundary, and is chain-local", + "state_root reserved sub-trees: gate is inert EXCEPT the armed set @regression the escrow locked-balance leaf is off everywhere EXCEPT the armed chain", + "state_root reserved sub-trees: gate is inert EXCEPT the armed set @regression the escrow-leaf SHADOW window is CLOSED everywhere, and ARMED WINS when both maps name a height", + "state_root reserved sub-trees: slot list @regression RESERVED_SUBTREES is exactly the non-v1 tail of merkle.STATE_SUBTREES, in order", + "state_root reserved sub-trees: slot list @regression the frozen slot list has exactly five names (a sixth would change every historical state_root)", + "state_root reserved sub-trees: slot list @regression there is no escrow sub-root: the locked leaf lives inside balances_root" + ], + "a3a695ffa9cdefe5": [ + "BlockBroadcaster broadcastStatus does nothing when no status data", + "BlockBroadcaster broadcastStatus sends status to all subscribers" + ], + "a588bab2c93363ed": [ + "E2E: state-commitment getNetBalance conformance (SQL minimalDecimal vs indexer mathjs bcsub) fuzz: 200 random ledgers render byte-identically", + "E2E: state-commitment getNetBalance conformance (SQL minimalDecimal vs indexer mathjs bcsub) renders hand-picked edge vectors byte-identically" + ], + "a5dcb3dfab180b59": [ + "ClientSync constructor handles empty SYNC_SOURCES", + "ClientSync constructor parses SYNC_SOURCES into array", + "ClientSync constructor trims whitespace from sources" + ], + "a5edff5ddc7a7030": [ + "Boundary: Source Array Parsing bootstrapFromSnapshot failure propagation retries with backoff, then succeeds on a later round", + "Boundary: Source Array Parsing bootstrapFromSnapshot failure propagation throws (does not silently return) when all sources are exhausted", + "Boundary: Source Array Parsing bootstrapFromSnapshot failure propagation throws when no sources are configured", + "Boundary: Source Array Parsing bootstrapRotateSources rotation (one round, returns boolean) does not recurse when only 1 source", + "Boundary: Source Array Parsing bootstrapRotateSources rotation (one round, returns boolean) no sources configured: returns false", + "Boundary: Source Array Parsing bootstrapRotateSources rotation (one round, returns boolean) rotates sources on failure with 2 sources", + "Boundary: Source Array Parsing bootstrapRotateSources rotation (one round, returns boolean) stops after exhausting all sources (no infinite recursion)", + "Boundary: Source Array Parsing constructor source parsing empty string \u2192 empty array", + "Boundary: Source Array Parsing constructor source parsing leading comma \u2192 filtered out", + "Boundary: Source Array Parsing constructor source parsing multiple commas \u2192 all empty strings filtered", + "Boundary: Source Array Parsing constructor source parsing only whitespace \u2192 empty array", + "Boundary: Source Array Parsing constructor source parsing single URL \u2192 1-element array", + "Boundary: Source Array Parsing constructor source parsing trailing comma \u2192 filtered out", + "Boundary: Source Array Parsing constructor source parsing two URLs \u2192 2-element array", + "Boundary: Source Array Parsing constructor source parsing whitespace trimmed" + ], + "a659b18e95ae431f": [ + "SnapshotBuilder paging-stream client-abort streamDispensers: swallows the abort and destroys gzip on client disconnect", + "SnapshotBuilder paging-stream client-abort streamTableRowsById: swallows the abort and destroys gzip on client disconnect" + ], + "a702de1223cc909f": [ + "E2E: Decoder DB Lifecycle Live WebSocket sync decoder block payload carries block_hash and omits indexer hashes", + "E2E: Decoder DB Lifecycle Live WebSocket sync replica receives decoder block events for blocks added post-bootstrap" + ], + "a86e3201d3a619c6": [ + "ClientRollback table lists has 12 block-scoped tables", + "ClientRollback table lists has action-scoped data tables" + ], "a88f7793e0424865": [ "Boundary: Hash Continuity Check block index continuity (exact +1 requirement) invalid: 0 \u2192 0 (repeat at zero)", "Boundary: Hash Continuity Check block index continuity (exact +1 requirement) invalid: 0 \u2192 2 (skip from zero)", @@ -1826,6 +2409,14 @@ "Boundary: Hash Continuity Check null prevBlockIndex (bootstrap) valid: null \u2192 999 (any block after bootstrap)", "Boundary: Hash Continuity Check null prevHashes valid: prevBlockIndex=5, prevHashes=null \u2192 skips check" ], + "a9b77afc5d938dab": [ + "HubClient credential tier asks for secrets on the initial fetch", + "HubClient credential tier falls back to the bulk key when the hub does not split the tier", + "HubClient credential tier keeps asking on the delta poll, cursor and all", + "HubClient credential tier names the cause once when the hub redacts anyway, not once per poll", + "HubClient credential tier says nothing when the hub served the credentials", + "HubClient credential tier sends HUB_CONFIG_SECRETS_API_KEY when the hub splits the credential tier" + ], "ae699f6978a9fbbd": [ "Database pool sizing per dbType applies per-dbType timeouts to the pool config", "Database pool sizing per dbType opens differently sized pools for the indexer and decoder DBs of the same chain", @@ -1845,6 +2436,18 @@ "poolSizing.resolvePoolSize() resolves every pool knob per dbType, not just the connection limit", "poolSizing.resolvePoolSize() sizes the indexer default to absorb the per-block fan-out at under 12x serialization" ], + "aed79f98d38bbde3": [ + "vendored checkpoint verifier (twin conformance) @regression a garbage-then-valid duplicate for one signer still PASSES (seen marked after verify)", + "vendored checkpoint verifier (twin conformance) @regression an empty validator set can never verify", + "vendored checkpoint verifier (twin conformance) @regression canonicalCheckpoint matches the ACTIVE SPV-root spec byte-for-byte (EQUIV-wrapped, roots committed)", + "vendored checkpoint verifier (twin conformance) @regression canonicalCheckpoint matches the ANCHOR spec byte-for-byte (SDK-pinned golden vector)", + "vendored checkpoint verifier (twin conformance) @regression rejects a checkpoint whose signer is not in the pinned set", + "vendored checkpoint verifier (twin conformance) @regression rejects a checkpoint with a tampered field (signature no longer matches the canonical)", + "vendored checkpoint verifier (twin conformance) @regression src/checkpoint.js is code-identical to the xchain-sdk copy (comments excepted)", + "vendored checkpoint verifier (twin conformance) @regression src/consensus/equivocation_header.js is code-identical to the xchain-sdk copy (comments excepted)", + "vendored checkpoint verifier (twin conformance) @regression src/consensus/stake_weighted_quorum.js is code-identical to the xchain-sdk copy (comments excepted)", + "vendored checkpoint verifier (twin conformance) @regression verifies a real Ed25519 quorum-signed checkpoint against its pinned set" + ], "af5a41ac8b61580f": [ "replicatedTables getReplicatedTables (decoder) covers the decoder per-block set", "replicatedTables getReplicatedTables (decoder) excludes mempool_transactions (non-deterministic across nodes)", @@ -1858,6 +2461,33 @@ "replicatedTables getReplicatedTables (indexer) returns a de-duplicated union of the per-scope lists", "replicatedTables getTopology defaults unknown dbTypes to the indexer topology" ], + "b03d7c4fb1f16f36": [ + "E2E: Disconnect/Resume Parity 10.5 Schema drift while disconnected (self-heal) a replica missing a replicated table re-applies the source schema and converges" + ], + "b0d1b3c568451adf": [ + "Integration: armed source handshake (server-tier rollout rehearsal) REST: a client carrying the upstream key reads a snapshot from an armed source", + "Integration: armed source handshake (server-tier rollout rehearsal) REST: the inbound guard key is NOT accepted upstream, so the two are truly separate", + "Integration: armed source handshake (server-tier rollout rehearsal) REST: the same read WITHOUT the upstream key is refused, which is the rollout order", + "Integration: armed source handshake (server-tier rollout rehearsal) WS: the upgrade is refused without it, so streaming sync stops too, not just bootstrap", + "Integration: armed source handshake (server-tier rollout rehearsal) WS: the upgrade succeeds only when the client carries the upstream key" + ], + "b12d9fe0288ee479": [ + "API rate-limit proxy trust security TRUST_PROXY=false does not let a spoofed header split one caller into separate buckets", + "API rate-limit proxy trust security TRUST_PROXY=false keys on the socket address and ignores a spoofed X-Forwarded-For", + "API rate-limit proxy trust security TRUST_PROXY=true collapses an IPv6 client to its network so rotation buys no new budget", + "API rate-limit proxy trust security TRUST_PROXY=true gives two different client addresses independent snapshot buckets", + "API rate-limit proxy trust security TRUST_PROXY=true ignores a client-supplied entry to the LEFT of the proxy-appended address", + "API rate-limit proxy trust security TRUST_PROXY=true ignores a long spoofed prefix, however many entries the client prepends", + "API rate-limit proxy trust security TRUST_PROXY=true keeps one client on separate buckets per chain, as the key intends", + "API rate-limit proxy trust security TRUST_PROXY=true keys on the client address the proxy appended, not the socket", + "API rate-limit proxy trust security startApi wiring does not let one client drain the snapshot budget of another", + "API rate-limit proxy trust security startApi wiring leaves the served app untrusting when TRUST_PROXY is unset", + "API rate-limit proxy trust security startApi wiring sets one trusted hop on the served app when TRUST_PROXY is on", + "API rate-limit proxy trust security startApi wiring shares one bucket across forged headers when TRUST_PROXY is unset", + "API rate-limit proxy trust security trustProxyHops disables forwarded-header trust when TRUST_PROXY is off", + "API rate-limit proxy trust security trustProxyHops never returns true, which express-rate-limit rejects as permissive", + "API rate-limit proxy trust security trustProxyHops returns exactly one hop when TRUST_PROXY is on" + ], "b146f330faa567f9": [ "balance-helpers @money @regression rebuildBalances() aggregates credits minus debits per (address_id, tick_id)", "balance-helpers @money @regression rebuildBalances() clears the table before reinserting (DELETE then INSERT, in order)", @@ -1879,73 +2509,139 @@ "balance-helpers @money @regression recomputeTokenSupplies() @money @regression runs one UPDATE per distinct token precision, keyed by decimals", "balance-helpers @money @regression recomputeTokenSupplies() @money @regression sums (credits - debits) + escrows at the EXACT scale and rounds ONCE at the token scale" ], - "b2efd648f4757794": [ - "config REPLICA_DB_READONLY defaults to false when unset", - "config REPLICA_DB_READONLY is false for \"false\", \"0\" and an empty value", - "config REPLICA_DB_READONLY is true for \"1\"", - "config REPLICA_DB_READONLY is true for \"true\" in any case", - "config SYNC_BOOTSTRAP_DEPTH defaults to an empty map", - "config SYNC_BOOTSTRAP_DEPTH folds the full coin name onto the same ticker key as the ticker spelling", - "config SYNC_BOOTSTRAP_DEPTH ignores a malformed key with no CHAIN_NETWORK split", - "config SYNC_BOOTSTRAP_DEPTH ignores non-positive / non-numeric depths", - "config SYNC_BOOTSTRAP_DEPTH parses SYNC_BOOTSTRAP_DEPTH__ into an uppercased CHAIN:NETWORK map", - "config SYNC_BOOTSTRAP_DEPTH records every raw env key it saw, whatever the value", - "config SYNC_BOOTSTRAP_DEPTH resolves the documented DOGE_TESTNET key to the key ClientSync looks up", - "config SYNC_EXCLUDE defaults to an empty array", - "config SYNC_EXCLUDE drops empty segments", - "config SYNC_EXCLUDE parses, trims, and deduplicates a comma list", - "config SYNC_META_RETENTION_BLOCKS defaults to 0 (retention disabled) when unset", - "config SYNC_META_RETENTION_BLOCKS is 0 for a non-numeric, empty or negative value", - "config SYNC_META_RETENTION_BLOCKS reads a positive window", - "config SYNC_MODE passthrough passes through the env value", - "config VERIFY_HASHES boolean returns false when set to \"FALSE\" (case-insensitive)", - "config VERIFY_HASHES boolean returns false when set to \"False\"", - "config VERIFY_HASHES boolean returns false when set to \"false\"", - "config VERIFY_HASHES boolean returns true for any value other than \"false\"", - "config VERIFY_HASHES boolean returns true when not set", - "config VERIFY_HASHES boolean returns true when set to \"true\"", - "config assertBootstrapDepthChains REFUSES a depth-0 key naming no discovered chain (0 is the full-snapshot branch)", - "config assertBootstrapDepthChains REFUSES a key whose chain was never discovered", - "config assertBootstrapDepthChains REFUSES a key whose network was never discovered", - "config assertBootstrapDepthChains REFUSES a malformed key with no CHAIN_NETWORK split", - "config assertBootstrapDepthChains REFUSES an unknown coin rather than defaulting it to depth 0", - "config assertBootstrapDepthChains accepts a config with no depth keys at all", - "config assertBootstrapDepthChains accepts a key naming a discovered chain (full-name spelling)", - "config assertBootstrapDepthChains accepts a key naming a discovered chain (ticker spelling)", - "config defaults returns correct defaults when no env vars set", - "config hardcoded values does not expose the retired WS_BACKPRESSURE_LIMIT", - "config hardcoded values includes CLIENT_RECONNECT_DELAY", - "config hardcoded values includes HASH_CONFIRM_TIMEOUT", - "config hardcoded values includes HUB_REPOLL_INTERVAL", - "config hardcoded values includes WS_BACKPRESSURE_MAX_BYTES default", - "config hardcoded values includes WS_BACKPRESSURE_STALL_MS default", - "config hardcoded values includes WS_PING_INTERVAL", - "config hardcoded values includes WS_STATUS_INTERVAL", - "config numeric coercion falls back to default for non-numeric SYNC_API_PORT", - "config numeric coercion parses BLOCK_POLL_INTERVAL as integer", - "config numeric coercion parses HUB_PORT as integer", - "config numeric coercion parses SYNC_API_PORT as integer", - "config string passthrough passes HUB_API_HOST", - "config string passthrough passes REPLICA_DB_HOST" + "b270a2265a5c716a": [ + "Integration: binary column replication (F2) full snapshot round-trips a blob byte-for-byte", + "Integration: binary column replication (F2) live block broadcast round-trips a blob byte-for-byte", + "Integration: binary column replication (F2) source stores true binary (sanity check: seed not corrupted by the helper)" + ], + "b2c127c405cfa5f5": [ + "ClientApplier applyFullSnapshot aborts the bootstrap (no commit) when local table enumeration fails with a non-schema-gap error", + "ClientApplier applyFullSnapshot binds the scoped state_tree_roots clear to the TICKER, not the full coin name @regression", + "ClientApplier applyFullSnapshot clears a source-empty local table absent from the payload (re-bootstrap staleness)", + "ClientApplier applyFullSnapshot clears tables in reverse order and inserts in forward order", + "ClientApplier applyFullSnapshot does NOT clear replica-local control tables sync_halt / sync_state on full-snapshot apply @regression", + "ClientApplier applyFullSnapshot fails closed on an invalid table name (rejects rather than silently dropping its rows)", + "ClientApplier applyFullSnapshot ignores node-local tables (mempool_transactions) shipped by an older source", + "ClientApplier applyFullSnapshot rolls back on error", + "ClientApplier applyFullSnapshot scoped-clears state_tree_roots at/above the snapshot height before seeding @regression", + "ClientApplier applyFullSnapshot skips null snapshot", + "ClientApplier applyFullSnapshot skips snapshot without tables", + "ClientApplier applyFullSnapshot throws on a schema-version mismatch before opening a transaction", + "ClientApplier applyFullSnapshot tolerates a genuine schema-gap error (1146) on local table enumeration" + ], + "b2eb6ba6aa6d5bb2": [ + "ClientRollback rollbackDecoder aborts (fail-closed) on a transient error in a tx-scoped delete (item 1848)", + "ClientRollback rollbackDecoder deletes tx-scoped tables by tx_index, then block-scoped tables by block_index", + "ClientRollback rollbackDecoder rolls back and rethrows when a block-scoped delete fails", + "ClientRollback rollbackDecoder routes a decoder DB through rollbackDecoder", + "ClientRollback rollbackDecoder skips tx-scoped deletes when no transactions are in range", + "ClientRollback rollbackDecoder swallows a missing tx-scoped table error (schema gap) and still completes" + ], + "b34bca1164f2f052": [ + "Rollback coverage guard @regression ATTEST v5 batch-head status restore is mirrored across xchain-indexer and xchain-sync (bespoke-logic drift guard)", + "Rollback coverage guard @regression COINPay match-status re-derive SQL is identical across xchain-indexer and xchain-sync (cross-repo drift guard)", + "Rollback coverage guard @regression F-1: tokens is not in any updatedRows mutation-class array (supply rides the ledger-driven pass + token_supply hash class)", + "Rollback coverage guard @regression F-2: buildStateHashData includes cooldown-maturity refund credit in credits class (maturity fixture)", + "Rollback coverage guard @regression F-2: buildStateHashData includes the anchor CRC-failure parent in the anchor_invalid preimage class (value fixture)", + "Rollback coverage guard @regression F-2: collectUpdatedRows returns the invalid_archive-stamped anchor parent by value (CRC-failure fixture)", + "Rollback coverage guard @regression F-5: OPERATOR_LOCAL_TABLES equals the registry-derived exclusion set plus the three permitted non-registry names", + "Rollback coverage guard @regression F-5: hub-mirrored tables are absent from the ServerPoller replicated universe (snapshot-exclusion contract)", + "Rollback coverage guard @regression ServerPoller streams index_addresses via the generic *_id pass (non-tx-interned completeness) @regression", + "Rollback coverage guard @regression VOTE polls re-open reset is mirrored across xchain-indexer and xchain-sync (bespoke-logic drift guard)", + "Rollback coverage guard @regression _cappedStakeWeightsSql is identical across xchain-indexer and xchain-sync (cross-repo drift guard)", + "Rollback coverage guard @regression _stakeWeightsSql is identical across xchain-indexer and xchain-sync (cross-repo drift guard)", + "Rollback coverage guard @regression anchor invalid_archive to unverified reset is mirrored across xchain-indexer and xchain-sync (bespoke-logic drift guard)", + "Rollback coverage guard @regression archive-head version set is [1] via the shared stateHash constant, consumed by updatedRows", + "Rollback coverage guard @regression archive_rollback_author_scope_gate.js is byte-identical across xchain-indexer and xchain-sync", + "Rollback coverage guard @regression attests is rolled back on the replica under its consolidated name, not the phantom split names", + "Rollback coverage guard @regression balances is recomputed, not blindly deleted by index", + "Rollback coverage guard @regression contract slash-restore SQL is identical across xchain-indexer and xchain-sync (cross-repo drift guard)", + "Rollback coverage guard @regression contractStateSubtree.test.js is byte-identical across xchain-sync and xchain-indexer, modulo sibling require depth (cross-repo twin)", + "Rollback coverage guard @regression contract_state_subtree.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression cooldown-maturity reversal is mirrored across xchain-indexer and xchain-sync (bespoke-logic drift guard)", + "Rollback coverage guard @regression cross-chain mirror reorg delete SQL is identical across xchain-indexer and xchain-sync (cross-repo drift guard)", + "Rollback coverage guard @regression db/subtree/node_store_rows.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression db/subtree/orphan_stats_reads.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression delegations deactivation reset is the threshold form on both sides (bespoke-logic drift guard)", + "Rollback coverage guard @regression demands a known network, because the publisher scope is armed", + "Rollback coverage guard @regression escrow re-derive SQL is identical across xchain-indexer and xchain-sync (cross-repo drift guard)", + "Rollback coverage guard @regression escrowLeafSubtree.test.js is byte-identical across xchain-sync and xchain-indexer, modulo sibling require depth (cross-repo twin)", + "Rollback coverage guard @regression escrow_leaf_subtree.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression every replicated DECODER table is handled on reorg", + "Rollback coverage guard @regression every replicated INDEXER table is handled on reorg", + "Rollback coverage guard @regression every table the source indexer rolls back is mirrored by ClientRollback (cross-repo drift guard)", + "Rollback coverage guard @regression every utf8mb4 widen entry is carried by a dated xchain-indexer migration (source/replica lockstep)", + "Rollback coverage guard @regression forward cooldown-credit selection mirrors the reverse delete keys (bespoke-logic drift guard)", + "Rollback coverage guard @regression forward derived-reward selection mirrors the derive_block_index rollback key, and the reconcile DELETE is mirrored (bespoke-logic drift guard)", + "Rollback coverage guard @regression forward recovery-reward selection mirrors the rollback key (bespoke-logic drift guard)", + "Rollback coverage guard @regression index id lookups are rolled back on the replica and mirror the source indexer (^id consensus)", + "Rollback coverage guard @regression merkle.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression pair-scoped IDX-2 markets deletion is mirrored across xchain-indexer and xchain-sync (parity drift guard)", + "Rollback coverage guard @regression prices is rolled back on the replica (regression: this was the drift that motivated the guard)", + "Rollback coverage guard @regression publisher-scope heights are the 2026-09-09 ruling values", + "Rollback coverage guard @regression registry replica-flagged orphan sweeps are mirrored across xchain-indexer and xchain-sync (parity drift guard)", + "Rollback coverage guard @regression sanity: ServerPoller declares a meaningful indexer table set", + "Rollback coverage guard @regression stake_weight_collation_gate.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression stateHash.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression stateSubtreeActivation.test.js is byte-identical across xchain-sync and xchain-indexer, modulo sibling require depth (cross-repo twin)", + "Rollback coverage guard @regression state_commitment_gate.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression state_hash.js selection predicates mirror the replicated mutation classes", + "Rollback coverage guard @regression state_subtree_gate.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression state_subtree_gate.js is byte-identical in xchain-explorer too (escrow-leaf liveness refusal)", + "Rollback coverage guard @regression state_subtree_gate.js is byte-identical in xchain-sdk too (client liveness export)", + "Rollback coverage guard @regression stream:special bucket tables join the reorg-coverage universe", + "Rollback coverage guard @regression swq_source_cap_gate.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression table_lifecycle.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression table_lifecycle/action_tables.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression table_lifecycle/block_and_special_tables.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "Rollback coverage guard @regression the replica calls the COINPay re-derive, and never on a truncated replica", + "Rollback coverage guard @regression updated_rows carries the BET status flips keyed by their stamp columns", + "Rollback coverage guard @regression updated_rows carries the DELEGATE v1 rotation rewrite keyed by the rotations journal window", + "Rollback coverage guard @regression updated_rows carries the VOTE poll finalization flip keyed by resolved_block", + "Rollback coverage guard @regression updated_rows carries the cooldown-maturity status_id flip keyed by cooldown_end_block", + "Rollback coverage guard @regression utf8mb4Columns.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)", + "dispensers convergence wording does not drift back ../../src/client/rollback.js does not restate the superseded dispensers convergence channel", + "dispensers convergence wording does not drift back ../../src/schema/replicated_tables.js does not restate the superseded dispensers convergence channel", + "dispensers convergence wording does not drift back ../../src/server/snapshot_builder.js does not restate the superseded dispensers convergence channel", + "dispensers convergence wording does not drift back ../../src/table_lifecycle.js does not restate the superseded dispensers convergence channel", + "dispensers convergence wording does not drift back ../../src/table_lifecycle/action_tables.js does not restate the superseded dispensers convergence channel", + "dispensers convergence wording does not drift back ../../src/table_lifecycle/block_and_special_tables.js does not restate the superseded dispensers convergence channel", + "dispensers convergence wording does not drift back ./rollback_coverage.test.js does not restate the superseded dispensers convergence channel", + "dispensers convergence wording does not drift back the decoderTxScopedTables comment names the reconcile channel" ], - "b34e13bb2c06de34": [ - "Boundary: HubClient Port Parsing _parsePort static method defaults to 3306 for non-numeric primary", - "Boundary: HubClient Port Parsing _parsePort static method defaults to 3306 when both are absent", - "Boundary: HubClient Port Parsing _parsePort static method defaults to 3306 when both are empty", - "Boundary: HubClient Port Parsing _parsePort static method defaults to 3306 when both are null", - "Boundary: HubClient Port Parsing _parsePort static method falls back to secondary when primary is empty string", - "Boundary: HubClient Port Parsing _parsePort static method falls back to secondary when primary is null", - "Boundary: HubClient Port Parsing _parsePort static method falls back to secondary when primary is undefined", - "Boundary: HubClient Port Parsing _parsePort static method float string truncated", - "Boundary: HubClient Port Parsing _parsePort static method integer 0 preserved", - "Boundary: HubClient Port Parsing _parsePort static method integer value (not string) works", - "Boundary: HubClient Port Parsing _parsePort static method negative port defaults to 3306", - "Boundary: HubClient Port Parsing _parsePort static method uses secondary when primary is non-numeric", - "Boundary: HubClient Port Parsing _parsePort static method valid port: returns as-is", - "Boundary: HubClient Port Parsing _parsePort static method zero: preserved (not treated as falsy)", - "Boundary: HubClient Port Parsing getIndexerConfigs integration defaults to 3306 when neither port field present", - "Boundary: HubClient Port Parsing getIndexerConfigs integration falls back to port when db_port absent", - "Boundary: HubClient Port Parsing getIndexerConfigs integration uses db_port from hub config" + "b3e2a0142aa3664a": [ + "SnapshotBuilder getOrderedTables excludes mempool_transactions (node-local, non-deterministic) like every other channel", + "SnapshotBuilder getOrderedTables orders priority tables first, trailing tables last, middle alphabetically", + "SnapshotBuilder getOrderedTables skips priority/trailing tables not in DB" + ], + "b4f0d893b0d9c977": [ + "SnapshotBuilder branch coverage streamIncrementalSnapshot fails closed (rejects + rolls back) on a transient per-table read error during incremental @regression", + "SnapshotBuilder branch coverage streamIncrementalSnapshot fails closed on a connection-drop (no errno) per-table read error during incremental @regression", + "SnapshotBuilder branch coverage streamIncrementalSnapshot indexer: scopes contract_emissions by block through the execution_index chain, not the action_index cursor @regression", + "SnapshotBuilder branch coverage streamIncrementalSnapshot indexer: still ships internal emissions when firstActionIndex is null @regression", + "SnapshotBuilder branch coverage streamIncrementalSnapshot ships matured cooldown refund credits when firstActionIndex is null (quiet window) @regression" + ], + "b57e7bf0add0a957": [ + "ClientSync: checkpoint-quorum anchor @regression HALTS when the checkpoint quorum is INVALID under the pinned set (rogue signer)", + "ClientSync: checkpoint-quorum anchor @regression HALTS when the quorum-signed state_root disagrees with the replica's own recompute", + "ClientSync: checkpoint-quorum anchor @regression REJECTS a checkpoint_seq regression (source rewound / withholding) without anchoring", + "ClientSync: checkpoint-quorum anchor @regression WARNS on a rootless checkpoint at a commitment-ACTIVE height (does not anchor, does not halt)", + "ClientSync: checkpoint-quorum anchor @regression does NOT halt when the quorum verifies and the state_root matches the replica", + "ClientSync: checkpoint-quorum anchor @regression does not warn freshness when the anchor is within CHECKPOINT_FRESHNESS_BLOCKS of the tip", + "ClientSync: checkpoint-quorum anchor @regression fetches the anchor from CHECKPOINT_ANCHOR_URL out-of-band when configured", + "ClientSync: checkpoint-quorum anchor @regression is INERT with no pinned set: no fetch, no halt", + "ClientSync: checkpoint-quorum anchor @regression never halts on a transport error (404 / network)", + "ClientSync: checkpoint-quorum anchor @regression records the verified checkpoint_seq high-water mark on success", + "ClientSync: checkpoint-quorum anchor @regression skips (no halt, no local read) when the replica has not reached the checkpoint height", + "ClientSync: checkpoint-quorum anchor @regression skips a genuinely pre-commitment checkpoint SILENTLY (snapshot below the flag-day)", + "ClientSync: checkpoint-quorum anchor @regression warns (no halt) when the anchor is staler than CHECKPOINT_FRESHNESS_BLOCKS behind the tip" + ], + "b642edb3ab6a5231": [ + "HubClient parsePort defaults to 3306 for a non-numeric or negative value", + "HubClient parsePort defaults to 3306 when both are absent", + "HubClient parsePort parses a numeric primary", + "HubClient parsePort preserves a literal 0 (does not fall through to default)", + "HubClient parsePort uses the fallback when primary is absent/empty" ], "b692b313f677d5c4": [ "/health halt verdict degrades on a halted client and names the halt", @@ -1953,6 +2649,13 @@ "/health halt verdict stays healthy for a running client on a healthy database", "/health halt verdict still degrades on an open circuit, halt or no halt" ], + "b6ab840e3149d748": [ + "ClientSync.fetchAndApplySchema multi-pass + fail-closed halt aborts the bootstrap round once a schema halt is recorded", + "ClientSync.fetchAndApplySchema multi-pass + fail-closed halt does NOT halt on a schema-fetch transport failure (not a DDL fault)", + "ClientSync.fetchAndApplySchema multi-pass + fail-closed halt records a durable halt when a genuine DDL fault survives the fixpoint", + "ClientSync.fetchAndApplySchema multi-pass + fail-closed halt records a durable halt when the column self-heal on an existing table is refused", + "ClientSync.fetchAndApplySchema multi-pass + fail-closed halt resolves FK ordering across passes without halting" + ], "b6f88326a1ba0d27": [ "BlockHasher: independent recompute conformance @regression RED: tampering a single replicated row changes the recomputed hash", "BlockHasher: independent recompute conformance @regression an all-empty block with no previous hash recomputes without error", @@ -1962,57 +2665,28 @@ "BlockHasher: independent recompute conformance @regression state_key collation gate (contract-state gather SQL) legacy folding collation when network/coin are omitted (pre-activation callers)", "BlockHasher: independent recompute conformance @regression state_key collation gate (contract-state gather SQL) pins COLLATE utf8_bin in GROUP BY and ORDER BY on regtest (armed from genesis)" ], - "b7040d6dffe594c1": [ - "SyncService _discoverChains SYNC_EXCLUDE drops a listed chain before any DB pool / ClientSync is created", - "SyncService _discoverChains client mode (source reachable): replicates schema, verifies tables, starts a ClientSync", - "SyncService _discoverChains client mode (source unreachable): falls through to server /schema fetch; still verifies sync tables for decoder", - "SyncService _discoverChains client mode REFUSES a bootstrap-depth key naming no discovered chain, before starting any sync", - "SyncService _discoverChains client mode REFUSES a malformed checkpoint pin override, before starting any sync", - "SyncService _discoverChains client mode accepts a bootstrap-depth key whose chain the hub published under its full name", - "SyncService _discoverChains client mode accepts a well-formed checkpoint pin override", - "SyncService _discoverChains server mode ignores bootstrap-depth keys entirely (the var governs nothing there)", - "SyncService _discoverChains server mode with REPLICA_DB_HOST re-serves from the local replica", - "SyncService _discoverChains server mode without REPLICA_DB_HOST connects to the hub-provided coordinates", - "SyncService _discoverChains skips already-known chains", - "SyncService _scheduleHubRepoll logs (does not throw) when a re-poll fails", - "SyncService _scheduleHubRepoll re-discovers chains on each interval tick and logs new chains", - "SyncService _scheduleHubRepoll sets up an interval", - "SyncService _startClientMode starts a ClientSync for each discovered database", - "SyncService _startClientSyncForChain creates a ClientSync once and is idempotent on the same key", - "SyncService _startClientSyncForChain exits the process when the background ClientSync crashes", - "SyncService _startPollerForChain does not create duplicate pollers", - "SyncService _startPollerForChain exits the process when the background poller crashes", - "SyncService _startServerMode creates broadcaster and snapshotBuilder", - "SyncService _startServerMode starts a poller for each discovered database", - "SyncService _waitForHub resolves immediately when hub is alive", - "SyncService _waitForHub retries until hub responds", - "SyncService _waitForHub timeout exits the process after MAX_HUB_WAIT_MS with no hub", - "SyncService constructor broadcaster is null initially", - "SyncService constructor creates a HashVerifier", - "SyncService constructor creates a HubClient", - "SyncService constructor initializes empty maps", - "SyncService getBroadcaster returns null before server mode started", - "SyncService getChains returns array of chain/network/dbType triples", - "SyncService getChains returns empty array when no chains", - "SyncService getClientSync returns the live sync or null", - "SyncService getClientSyncState omits halt info for a healthy sync", - "SyncService getClientSyncState reports a live sync, including halt info when halted", - "SyncService getClientSyncState returns nulls/false when no sync exists for the key", - "SyncService getDatabase returns db for known chain/network (indexer default)", - "SyncService getDatabase returns decoder db when dbType=decoder is requested", - "SyncService getDatabase returns null for unknown chain/network", - "SyncService getHubConfigAgeSeconds returns null when the hub has never answered", - "SyncService getHubConfigAgeSeconds returns whole seconds since the last successful fetch", - "SyncService getSnapshotBuilder returns null before server mode started", - "SyncService getTransparencyLog creates a temporary TransparencyLog when no poller", - "SyncService getTransparencyLog returns null for unknown chain/network", - "SyncService getTransparencyLog returns poller transparency log when poller exists", - "SyncService mode branching in start calls _startClientMode for client mode", - "SyncService mode branching in start calls _startServerMode for server mode", - "SyncService startup readiness (isReady) gates GET /health on readiness before the per-chain loop", - "SyncService startup readiness (isReady) is not ready before start()", - "SyncService startup readiness (isReady) is ready after start() completes with a legitimately empty chain set", - "SyncService startup readiness (isReady) is still not ready while start() waits on the hub" + "b7dd6bd9b2a33a4e": [ + "SnapshotBuilder streamIncrementalSnapshot decoder: re-dumps the events table in full on incremental", + "SnapshotBuilder streamIncrementalSnapshot indexer: re-dumps index_* lookup tables in full on incremental", + "SnapshotBuilder streamIncrementalSnapshot indexer: re-dumps the events audit log in full on incremental, paged by id", + "SnapshotBuilder streamIncrementalSnapshot returns 404 when no blocks after sinceBlock", + "SnapshotBuilder streamIncrementalSnapshot returns 404 when no blocks at all", + "SnapshotBuilder streamIncrementalSnapshot skipLookups omits the .index lookup tables but keeps block-scoped data", + "SnapshotBuilder streamIncrementalSnapshot streams incremental data with since_block field" + ], + "b80b57d0513b68fe": [ + "E2E: Decoder DB Lifecycle Proxy-trust rate-limit wiring gives distinct forwarded clients independent snapshot budgets", + "E2E: Decoder DB Lifecycle Proxy-trust rate-limit wiring stops at the one address the proxy vouched for, so a forged prefix buys no budget" + ], + "b80dca04c74b600c": [ + "HubClient getallconfigs cursor + watermark handling merges a delta against the cursor it previously sent", + "HubClient getallconfigs cursor + watermark handling records lastSuccessfulFetchAt on a successful bare-map fetch and resets the cursor", + "HubClient getallconfigs cursor + watermark handling resets the cursor and re-fetches full when it fails over to a different endpoint", + "HubClient getallconfigs cursor + watermark handling treats a watermarked payload as a full tree on the first fetch (no cursor sent yet)", + "HubClient getallconfigs cursor + watermark handling unwraps a { configs, seq } payload (no watermark) and resets the cursor" + ], + "b92e0d472730652e": [ + "SyncService getClientSync returns the live sync or null" ], "bcf51d25df891659": [ "/status persistent replica gaps asks for the gaps of the row being built, not a default chain", @@ -2020,6 +2694,22 @@ "/status persistent replica gaps publishes the gap beside an otherwise green row", "/status persistent replica gaps stays an empty array when no live client sync exposes the surface" ], + "bd1e405ed8d1de94": [ + "05 Sustained Sync processes blocks continuously for 60000ms without degradation" + ], + "be30d095ec85b25c": [ + "train_activation twin + canon parity holds TRAIN_ACTIVATION value-equal to the canonical map at /xchain-documentation/protocol/constants.js", + "train_activation twin + canon parity holds src/train_activation.js byte-identical to the twin at /xchain-indexer/src/consensus/gates/train_gate.js", + "train_activation twin + canon parity reports skipped and names what it looked for when a sibling is absent", + "train_activation twin + canon parity still exports the gate the parity cases compare, whatever the checkout state", + "train_activation twin + canon parity throws rather than skipping on an absent sibling when XCHAIN_REQUIRE_SIBLINGS=1" + ], + "be748fea997da5e8": [ + "ClientSync: strict cross-source gate survives catch-up (M-22) a second source confirming the block clears the strict block and unblocks catch-up", + "ClientSync: strict cross-source gate survives catch-up (M-22) a strict cross-source timeout records the block and retains its pending hash", + "ClientSync: strict cross-source gate survives catch-up (M-22) catch-up proceeds normally once no strict block is pending", + "ClientSync: strict cross-source gate survives catch-up (M-22) incrementalCatchUp refuses to run single-source while a strict block is pending" + ], "be9b26be638dfbe0": [ "deactivation_block sync-mirror frozen per-chain ACTIVATION_DELAY_BLOCKS a supplied-but-unknown coin is a hard error (never a silent wrong delay)", "deactivation_block sync-mirror frozen per-chain ACTIVATION_DELAY_BLOCKS an omitted coin leaves activationDelay null (legacy path)", @@ -2032,12 +2722,99 @@ "deactivation_block sync-mirror rollback emits the four re-NULL resets when a coin is set stakes reset joins unstakes and matches the EXACT stamped value (precise, not blanket)", "deactivation_block sync-mirror without a coin the mirror is skipped (and warns, not silent) emits zero resets and warns" ], + "be9bdba4e50a9357": [ + "Integration: Full Lifecycle bootstrap \u2192 live sync \u2192 reorg \u2192 recovery completes full lifecycle correctly" + ], + "c01052b400b95da9": [ + "ClientSync logGap throttling logs the first occurrence immediately", + "ClientSync logGap throttling resets the suppressed count after emitting a summary", + "ClientSync logGap throttling suppresses repeats within the window, then emits one summary with the count" + ], + "c19f60997c7483e1": [ + "ClientSync bootstrap-failure gating (empty-replica defect) bootstrapFromSnapshot rejects with BootstrapExhaustedError once all retry rounds exhaust", + "ClientSync bootstrap-failure gating (empty-replica defect) handleBlock refuses to apply a non-genesis block onto an empty replica", + "ClientSync bootstrap-failure gating (empty-replica defect) start() propagates a permanent bootstrap failure without live-following", + "ClientSync bootstrap-failure gating (empty-replica defect) start() refuses live-follow when bootstrap leaves the replica empty" + ], + "c4e8870b7986e321": [ + "ServerPoller buildBlockPayload collects both decoder blocks hash ids under the shared *_hash_id rule @regression", + "ServerPoller buildBlockPayload does not run the generic index pass for the decoder", + "ServerPoller buildBlockPayload extracts the remaining indexer index tables from referenced _id columns", + "ServerPoller buildBlockPayload fails closed on a TRANSIENT updated_rows collection error (deadlock 1213) so the block is retried, not broadcast without updated_rows @regression", + "ServerPoller buildBlockPayload fetches index_addresses by source_id from transactions", + "ServerPoller buildBlockPayload fetches index_transactions by referenced IDs", + "ServerPoller buildBlockPayload streams the blocks.state_hash_id index_transactions row with the live block @regression" + ], + "c54a906a079d6748": [ + "health/carrier_logic: the published carrier logic digest /health carries the digest as its own field beside v2 and version 2, with no _v2 alias", + "health/carrier_logic: the published carrier logic digest equals the pin module digest of the committed pin, with no second formula in effect", + "health/carrier_logic: the published carrier logic digest is memoised per process", + "health/carrier_logic: the published carrier logic digest never requires the pin module or the tokenizer, so a src-only image can load it", + "health/carrier_logic: the published carrier logic digest publishes the literal UNREADABLE when the pin is absent, never a hex and never a throw", + "health/carrier_logic: the published carrier logic digest reads the pin two directories up from src/health, so a copy with the pin publishes the hex" + ], "c54bb56b0f6fae1f": [ "state_hash: replication-integrity recompute conformance @regression RED: a missing backdated credit (dropped apply) changes the state_hash", "state_hash: replication-integrity recompute conformance @regression RED: tampering any single mutated row changes the state_hash", "state_hash: replication-integrity recompute conformance @regression builds the fixed-order preimage covering every mutation class", "state_hash: replication-integrity recompute conformance @regression reproduces the indexer-authentic committed state_hash from canned resolved rows" ], + "c5c4b726fc0811ec": [ + "stateCommitment: stakes subtree rebuilds only on change @regression a CHANGED stake set rebuilds and moves the root", + "stateCommitment: stakes subtree rebuilds only on change @regression a GAP in block continuity rebuilds, even with an identical stake set", + "stateCommitment: stakes subtree rebuilds only on change @regression a RUN of unchanged blocks writes nothing after the first, not every other one", + "stateCommitment: stakes subtree rebuilds only on change @regression a cold start has no memo, so the first block after a restart rebuilds", + "stateCommitment: stakes subtree rebuilds only on change @regression a different chain or network never reads the other one's memo", + "stateCommitment: stakes subtree rebuilds only on change @regression a memoized root missing from the store rebuilds instead of committing it", + "stateCommitment: stakes subtree rebuilds only on change @regression an empty stake set is memoized without a store read that cannot succeed", + "stateCommitment: stakes subtree rebuilds only on change @regression an unchanged stake set on the next block writes NOTHING and returns the same root", + "stateCommitment: stakes subtree rebuilds only on change @regression re-parsing the SAME block index rebuilds rather than trusting a sibling memo", + "stateCommitment: stakes subtree rebuilds only on change @regression reordering the same stake entries still hits, because buildFull is order-independent", + "stateCommitment: stakes subtree rebuilds only on change @regression the memoized root is byte-identical to what buildFull would have returned" + ], + "c7cbd5dc4224f664": [ + "validation validateIdentifier accepts digits and underscores", + "validation validateIdentifier accepts exactly 64 characters", + "validation validateIdentifier accepts mixed case with underscores", + "validation validateIdentifier accepts single character", + "validation validateIdentifier accepts single lowercase word", + "validation validateIdentifier rejects 65-character string", + "validation validateIdentifier rejects SQL injection attempt", + "validation validateIdentifier rejects backtick injection", + "validation validateIdentifier rejects dash", + "validation validateIdentifier rejects dot notation", + "validation validateIdentifier rejects empty string", + "validation validateIdentifier rejects non-string (number)", + "validation validateIdentifier rejects null", + "validation validateIdentifier rejects null byte", + "validation validateIdentifier rejects path traversal", + "validation validateIdentifier rejects semicolons", + "validation validateIdentifier rejects spaces", + "validation validateIdentifier rejects undefined", + "validation validateIdentifier rejects unicode characters" + ], + "c7d55f705a9a8f0d": [ + "validation validateDdl accepts CREATE TABLE IF NOT EXISTS with backticks", + "validation validateDdl accepts DDL with leading whitespace", + "validation validateDdl accepts canonical CREATE TABLE", + "validation validateDdl accepts lowercase create table", + "validation validateDdl accepts multiline DDL with indexes and ENGINE", + "validation validateDdl rejects CREATE EVENT", + "validation validateDdl rejects CREATE FUNCTION", + "validation validateDdl rejects CREATE PROCEDURE", + "validation validateDdl rejects CREATE TRIGGER", + "validation validateDdl rejects CREATE VIEW", + "validation validateDdl rejects DROP TABLE", + "validation validateDdl rejects EXEC injection after semicolon", + "validation validateDdl rejects case-insensitive banned keywords", + "validation validateDdl rejects empty string", + "validation validateDdl rejects multi-statement injection with CREATE TRIGGER after semicolon", + "validation validateDdl rejects multi-statement injection with DROP after semicolon", + "validation validateDdl rejects non-string (array)", + "validation validateDdl rejects non-string (object)", + "validation validateDdl rejects null", + "validation validateDdl rejects undefined" + ], "c7ffd8486a3a6f7e": [ "collectRedrivenValidatorRewards distinguishes archive rows that differ only in round_qualifier", "collectRedrivenValidatorRewards distinguishes rows that share columns but differ in round_reference", @@ -2048,6 +2825,53 @@ "collectRedrivenValidatorRewards selects by the applied_block window with the survivors-only backdating guard", "collectRedrivenValidatorRewards swallows ONLY a schema gap (1146/1054); a transient fault propagates so the block is retried" ], + "c887799f86d69a43": [ + "ClientSync: state_hash apply-time integrity halt @regression HALTS when the apply-time state_hash recompute disagrees with the source", + "ClientSync: state_hash apply-time integrity halt @regression SKIPS the check (no recompute, no halt) when the source sent a NULL state_hash (pre-feature block)", + "ClientSync: state_hash apply-time integrity halt @regression does NOT halt when the recomputed state_hash matches (clean block advances)", + "ClientSync: state_hash apply-time integrity halt @regression opts out cleanly when VERIFY_STATE_HASH=false (throwaway mirrors)" + ], + "c8f08c761facce4a": [ + "Database halt methods clearHalt: returns 0 when result is falsy", + "Database halt methods clearHalt: returns affectedRows", + "Database halt methods getActiveHalt: PROPAGATES a transient query error (fail-closed, not a silent [])", + "Database halt methods getActiveHalt: returns null when no rows", + "Database halt methods getActiveHalt: returns the first row when rows present", + "Database halt methods recordHalt: idempotent (returns existing when block_index matches)", + "Database halt methods recordHalt: inserts new halt when none active", + "Database.getActions() returns rows from actions table", + "Database.getDatabaseStats() returns rows from information_schema query", + "Database.getEmissionRowsForBlock() joins through contract_executions on execution_index (includes NULL action_index rows)", + "Database.getEmissionRowsForBlock() selects only the four protocol columns, never em.* (would carry the id PK)", + "Database.getTableCount() propagates the database error with errno intact when the table is absent", + "Database.getTableCount() returns count as Number", + "Database.getTransactions() returns rows from transactions table", + "Database.getTxScopedRows() queries with tx join", + "Database.listExistingTables() THROWS rather than reporting an empty schema when the listing fails", + "Database.listExistingTables() reports a table the caller should skip", + "Database.listExistingTables() returns the table names as a Set, tolerating either column case", + "Database.streamTableRows() runs ONE un-paged ordered query on the given snapshot connection", + "Database.truncateTable() calls doQuery with TRUNCATE TABLE" + ], + "c99af0a2bafdfce4": [ + "Integration: REST API GET /status/:dbType/:chain/:network returns 404 for unknown chain", + "Integration: REST API GET /status/:dbType/:chain/:network returns status for specific chain" + ], + "c99ff09c7317dddf": [ + "Integration: index-map parity over HTTP (e2e) divergence: equal-count swapped identity fires advisory mismatch, no halt", + "Integration: index-map parity over HTTP (e2e) faithful replica: /status checksum matches, no mismatch, no counter", + "Integration: index-map parity over HTTP (e2e) recovery: faithful again raises no new mismatch (counter steady)" + ], + "ca3ce40121d57267": [ + "BlockBroadcaster send clears the backpressure stall window when the buffer drains (item 5410)", + "BlockBroadcaster send closes ws when the send buffer exceeds the byte ceiling (item 5410)", + "BlockBroadcaster send skips non-OPEN WebSocket" + ], + "ca3ef17f876157b0": [ + "ClientSync healSchemaIfStale debounces to one heal per minute", + "ClientSync healSchemaIfStale heals on missing table (1146) and missing column (1054)", + "ClientSync healSchemaIfStale ignores non-schema errors and null errors" + ], "ca8fa416b5e8a763": [ "observability/installObservability buckets an unmatched path by first segment so URLs cannot explode cardinality", "observability/installObservability gates the endpoint behind METRICS_TOKEN when one is configured", @@ -2118,6 +2942,146 @@ "observability/patchConsole resolves printf format strings and keeps an Error stack, via util.format", "observability/patchConsole routes console.* through the shim, mapping log to info" ], + "cad1d26d53c24f5a": [ + "read-snapshot connection isolation (#3732) @integration a held read snapshot survives a concurrent writer transaction", + "read-snapshot connection isolation (#3732) @integration two concurrent read snapshots use independent connections" + ], + "cc72fad7b0a4aab2": [ + "BlockBroadcaster security getIp: TRUST_PROXY=false ignores x-forwarded-for when TRUST_PROXY is false", + "BlockBroadcaster security getIp: TRUST_PROXY=false returns unknown when no socket address and no forwarded header", + "BlockBroadcaster security getIp: TRUST_PROXY=false uses socket remoteAddress when no forwarded header", + "BlockBroadcaster security getIp: TRUST_PROXY=true a forged leading entry does not become the rate-limit key", + "BlockBroadcaster security getIp: TRUST_PROXY=true a long forged prefix still keys on the appended rightmost address", + "BlockBroadcaster security getIp: TRUST_PROXY=true falls back to socket on a trailing-comma header rather than keying on an empty string", + "BlockBroadcaster security getIp: TRUST_PROXY=true falls back to socket on a whitespace-only header rather than keying on an empty string", + "BlockBroadcaster security getIp: TRUST_PROXY=true falls back to socket when x-forwarded-for absent and TRUST_PROXY true", + "BlockBroadcaster security getIp: TRUST_PROXY=true keys on the address the trusted proxy appended, not the client-supplied leading entry", + "BlockBroadcaster security getIp: TRUST_PROXY=true trims whitespace around the appended address", + "BlockBroadcaster security getIp: TRUST_PROXY=true uses x-forwarded-for when TRUST_PROXY is true", + "BlockBroadcaster security per-IP limit with TRUST_PROXY=false different socket IPs are not affected by per-IP limit", + "BlockBroadcaster security per-IP limit with TRUST_PROXY=false spoofed x-forwarded-for cannot bypass per-IP limit", + "BlockBroadcaster security per-IP limit with TRUST_PROXY=true a client cannot exhaust another client bucket by claiming its address in the prefix", + "BlockBroadcaster security per-IP limit with TRUST_PROXY=true rotating the forged leading entry does not buy extra connections", + "BlockBroadcaster security per-IP limit with TRUST_PROXY=true two real clients behind the proxy get independent buckets" + ], + "cefc03d7e7861167": [ + "ClientRollback balance-rebuild error handling logs (does not rethrow) a 1146 error from rebuildBalances", + "ClientRollback balance-rebuild error handling logs (does not rethrow) a 1146 error from recomputeTokenSupplies", + "ClientRollback balance-rebuild error handling recomputes token supplies after rebuilding balances (before commit)", + "ClientRollback balance-rebuild error handling rethrows a non-1146 error from rebuildBalances", + "ClientRollback balance-rebuild error handling rethrows a non-1146 error from recomputeTokenSupplies" + ], + "cf73b1d25cf81b8c": [ + "ClientApplier applyBlock accepts a live block payload with a matching schema_version", + "ClientApplier applyBlock accepts a live block payload without schema_version (pre-5250 server)", + "ClientApplier applyBlock applies block in a transaction", + "ClientApplier applyBlock applies the genesis block (block_index 0) instead of silently dropping it", + "ClientApplier applyBlock does NOT rebuild balances on a decoder replica", + "ClientApplier applyBlock does not issue the reconcile delete mirror when the block carries no reconcile-log rows", + "ClientApplier applyBlock mirrors the anchor-reward winner collapse from this block's reconcile-log pre-images (keyed delete, after inserts, in-txn)", + "ClientApplier applyBlock never opens a transaction when the duplicate guard read faults", + "ClientApplier applyBlock reads the duplicate guard fail-CLOSED (opts.rethrow)", + "ClientApplier applyBlock rebuilds balances when an indexer payload touches credits/debits", + "ClientApplier applyBlock rejects a live block payload with a mismatched schema_version", + "ClientApplier applyBlock rolls back on error", + "ClientApplier applyBlock skips empty table arrays", + "ClientApplier applyBlock skips existing block (duplicate detection)", + "ClientApplier applyBlock skips null payload", + "ClientApplier applyBlock skips payload without block_index", + "ClientApplier applyBlock skips payload without data", + "ClientApplier rebuildBalances error handling rethrows a non-1146 error on rebuildBalances", + "ClientApplier rebuildBalances error handling swallows a 1146 (table-missing) error on rebuildBalances", + "ClientApplier scoped balance rebuilds falls back to the FULL rebuild when a row is missing its ids", + "ClientApplier scoped balance rebuilds falls back to the FULL rebuild when the touched-id set exceeds the IN-list cap", + "ClientApplier scoped balance rebuilds passes the distinct touched (address_id, tick_id) ids to rebuildBalances", + "ClientApplier scoped balance rebuilds scopes the incremental catch-up rebuild the same way", + "ClientApplier scoped balance rebuilds skips the rebuild entirely when the touched tables are empty arrays" + ], + "cf99cbc50f631839": [ + "stateCommitment: batched SMT node writes @regression DbNodeStore itself exposes putMany, so the real block path never takes the fallback", + "stateCommitment: batched SMT node writes @regression a key update costs ONE store write call, not one per tree level", + "stateCommitment: batched SMT node writes @regression a store with no putMany still gets the identical rows, one call per level", + "stateCommitment: batched SMT node writes @regression batched writes emit the SAME root and the SAME node set as per-node writes", + "stateCommitment: batched SMT node writes @regression deletes batch the same way and still return the tree to the empty root", + "stateCommitment: batched SMT node writes @regression the BTC stakes-subtree shape stays bounded: 49 keys cost 49 write calls, not 12,544", + "stateCommitment: batched SMT node writes @regression the batch is flushed before update() returns, so the next descend sees it" + ], + "d0ebbb448921f133": [ + "state_root reserved sub-trees: gate is inert EXCEPT the armed set @regression every populated activation key is coin-qualified (:)", + "state_root reserved sub-trees: gate is inert EXCEPT the armed set @regression no environment variable can arm a slot", + "state_root reserved sub-trees: gateSubRoots @regression drops every candidate on every INERT chain, returning null", + "state_root reserved sub-trees: gateSubRoots @regression fails closed on a malformed MAP threshold, not just a malformed query height", + "state_root reserved sub-trees: gateSubRoots @regression fails closed on an unparseable height", + "state_root reserved sub-trees: gateSubRoots @regression opens for exactly the armed slot, chain and height once a height is set", + "state_root reserved sub-trees: gateSubRoots @regression passes ONLY the armed slot through on the armed chain", + "state_root reserved sub-trees: gateSubRoots @regression returns null for null / empty candidates", + "state_root reserved sub-trees: gateSubRoots @regression the block paths hand assembleStateRoot only gateSubRoots output (the gate is the only permitted writer)", + "state_root reserved sub-trees: gateSubRoots @regression throws on an unknown slot name rather than dropping it silently" + ], + "d1d68be89e493fba": [ + "Smoke: Server Mode GET /schema returns tables", + "Smoke: Server Mode GET /snapshot returns decompressible data", + "Smoke: Server Mode GET /status returns 200 with block data", + "Smoke: Server Mode WebSocket connection accepted and receives status", + "Smoke: Server Mode config loads with valid defaults", + "Smoke: Server Mode getBlockHashRow returns hash fields", + "Smoke: Server Mode getLastBlock returns a value", + "Smoke: Server Mode hub is reachable", + "Smoke: Server Mode hub returns indexer configs", + "Smoke: Server Mode poll cycle completes without error", + "Smoke: Server Mode source DB connection succeeds" + ], + "d22ec38d3512da31": [ + "Integration: scoped balance rebuilds balances ClientApplier.applyBlock drives the scoped rebuild end-to-end", + "Integration: scoped balance rebuilds balances a scoped rebuild leaves the table exactly as a full rebuild would" + ], + "d2fffeabd095588e": [ + "SyncService getClientSyncState omits halt info for a healthy sync", + "SyncService getClientSyncState reports a live sync, including halt info when halted", + "SyncService getClientSyncState returns nulls/false when no sync exists for the key" + ], + "d43f78d5b62fbee6": [ + "SyncService constructor broadcaster is null initially", + "SyncService constructor creates a HashVerifier", + "SyncService constructor creates a HubClient", + "SyncService constructor initializes empty maps", + "SyncService getBroadcaster returns null before server mode started", + "SyncService getChains returns array of chain/network/dbType triples", + "SyncService getChains returns empty array when no chains", + "SyncService getDatabase returns db for known chain/network (indexer default)", + "SyncService getDatabase returns decoder db when dbType=decoder is requested", + "SyncService getDatabase returns null for unknown chain/network", + "SyncService getSnapshotBuilder returns null before server mode started", + "SyncService getTransparencyLog creates a temporary TransparencyLog when no poller", + "SyncService getTransparencyLog returns null for unknown chain/network", + "SyncService getTransparencyLog returns poller transparency log when poller exists", + "SyncService waitForHub resolves immediately when hub is alive", + "SyncService waitForHub retries until hub responds" + ], + "d491968d8d9a3eed": [ + "SyncService startClientSyncForChain creates a ClientSync once and is idempotent on the same key", + "SyncService startClientSyncForChain exits the process when the background ClientSync crashes" + ], + "d54620a13360f8b5": [ + "Database halt methods recordHalt: inserts new halt when existing block_index differs", + "Database halt methods recordHalt: returns null (not a throw) when the post-insert read throws", + "Database halt methods recordHalt: still INSERTs when the idempotency pre-check read throws (durability first)", + "Database halt methods recordHalt: uses default \"divergence\" when reason is null, defaults mismatches/sources to []", + "Database.replicateSchema() calls addMissingColumns for already-existing tables", + "Database.replicateSchema() creates a missing table and calls ensureReplicatedColumns", + "Database.replicateSchema() handles CREATE TABLE throw (deferred) and executes retry block", + "Database.replicateSchema() handles TABLE_NAME (uppercase) keys from information_schema rows", + "Database.replicateSchema() retry block: skips invalid table name", + "Database.replicateSchema() skips DDL that fails validateDdl (invalid DDL)", + "Database.replicateSchema() skips invalid table name (validateIdentifier fail)", + "Database.replicateSchema() skips table when SHOW CREATE TABLE returns empty rows", + "Database.replicateSchema() skips table when SHOW CREATE TABLE row has no Create Table key" + ], + "d6e6a07ac37b541c": [ + "ServerPoller buildBlockPayload fails closed on a TRANSIENT per-table read error (deadlock 1213) so the block is retried, not broadcast incomplete @regression", + "ServerPoller buildBlockPayload ships state_root NULL for burst blocks but keeps balances/merkle roots (@regression)", + "ServerPoller buildBlockPayload skips a per-table SCHEMA-GAP read error (errno 1146) and still builds the block @regression" + ], "d7ac1268f904a175": [ "ServerPoller action-scoped non-empty-table probe emits a payload byte-identical to the unprobed build while querying only non-empty tables", "ServerPoller action-scoped non-empty-table probe falls back to querying every table when the probe throws", @@ -2126,11 +3090,51 @@ "ServerPoller action-scoped non-empty-table probe reports probe_queries in the metric so a silent regression to the N+1 is visible", "ServerPoller action-scoped non-empty-table probe still streams contract_emissions when the probe reports nothing" ], + "d81e2076ef5e60ee": [ + "Integration: index-map parity (advisory, NON-consensus) case 1: faithful replica matches the source (NULL-block source row excluded)", + "Integration: index-map parity (advisory, NON-consensus) case 2: equal row count + swapped identity diverges (the INSERT IGNORE bug)", + "Integration: index-map parity (advisory, NON-consensus) case 3: a NULL-block replica row the source lacks raises no false alarm", + "Integration: index-map parity (advisory, NON-consensus) case 4: advisory mismatch counter persists + increments (real sync_state)", + "Integration: index-map parity (advisory, NON-consensus) case 5: the bound is honored (rows above uptoBlock are excluded)" + ], + "d87bf948f96ea270": [ + "HubClient getDecoderConfigs extracts xchain-decoder entries", + "HubClient getDecoderConfigs skips non-object coin/network values defensively" + ], "d8d1e52267ea606f": [ "cross-repo sibling coverage (what this run could NOT verify) declares every sibling it lists in .ci-siblings, so the venue ships them", "cross-repo sibling coverage (what this run could NOT verify) reports every sibling it looked for, so the list itself cannot rot silently", "cross-repo sibling coverage (what this run could NOT verify) resolves every sibling checkout the cross-repo guards depend on" ], + "db43ccc2db666f97": [ + "ClientSync truncated catch-up decoder chain is truncated by the same depth and pages lookups + skip_lookups", + "ClientSync truncated catch-up depth-key resolution against the real config parse the documented SYNC_BOOTSTRAP_DEPTH_DOGE_TESTNET reaches a hub-named \"dogecoin\" chain", + "ClientSync truncated catch-up depth-key resolution against the real config parse the full-name SYNC_BOOTSTRAP_DEPTH_DOGECOIN_TESTNET resolves to the same depth", + "ClientSync truncated catch-up full-history chain does NOT page lookups and uses no skip_lookups (unchanged path)", + "ClientSync truncated catch-up re-pages lookups AFTER the block window apply so (T1..T2] FK targets are present before recompute", + "ClientSync truncated catch-up truncated chain pages lookups then fetches the block window with skip_lookups=1" + ], + "db839ea0e9db1207": [ + "Database.addMissingColumns(): edge branches skips (logs error) a column with an invalid identifier name", + "Database.addMissingColumns(): edge branches warns and skips a column when extractColumnDefinition returns null", + "Database.ensureReplicatedColumns() adds missing columns for indexer dbType", + "Database.ensureReplicatedColumns() returns immediately for decoder dbType (no-op)", + "Database.ensureReplicatedColumns() skips column when column already exists on replica", + "Database.ensureReplicatedColumns() skips column when table does not exist on replica", + "Database.getLastBlock() PROPAGATES a query error with opts.rethrow (fail-closed resume cursor)", + "Database.getLastBlock() returns Number when rows contain a block_index", + "Database.getLastBlock() returns null when row.block_index is null", + "Database.getLastBlock() returns null when rows is empty", + "Database.getLastBlock() swallows a query error and returns null by default (fail-soft preserved)", + "Database.getReplicaStatus() falls back to the pre-10.5 SLAVE spelling", + "Database.getReplicaStatus() reads a healthy replica row", + "Database.getReplicaStatus() reports a stopped SQL thread as running:false with NULL, never 0 behind", + "Database.getReplicaStatus() reports not-a-replica on an empty result set (primary / co-located source)", + "Database.getReplicaStatus() returns an unknown result when the grant is missing, never a healthy one", + "Database.verifySyncTables() createTableFromFile: executes all statements from file", + "Database.verifySyncTables() indexer dbType: applies the full sync-owned set including sync_halt", + "Database.verifySyncTables() throws (via util.throwError) when query fails" + ], "dcf4bd51a912a4e0": [ "ClientSync status tick fires the stale dispensers reconcile clears the in-flight flag even when the reconcile rejects", "ClientSync status tick fires the stale dispensers reconcile does not advance the every-Nth catch-up counter", @@ -2148,37 +3152,6 @@ "ClientSync.dispenserReconcileIntervalDue (wall-clock term) leaves the catch-up cycle counter alone", "ClientSync.dispenserReconcileIntervalDue (wall-clock term) treats 0 as disabling the wall-clock trigger" ], - "ddfedb4e7f598989": [ - "train_activation twin + canon parity holds TRAIN_ACTIVATION value-equal to the canonical map at /xchain-documentation/protocol/constants.js", - "train_activation twin + canon parity holds src/train_activation.js byte-identical to the twin at /xchain-indexer/src/train_activation.js", - "train_activation twin + canon parity reports skipped and names what it looked for when a sibling is absent", - "train_activation twin + canon parity still exports the gate the parity cases compare, whatever the checkout state", - "train_activation twin + canon parity throws rather than skipping on an absent sibling when XCHAIN_REQUIRE_SIBLINGS=1" - ], - "de3963533a177029": [ - "XCHAIN_ESC locked leaf: arming moves balances_root @regression an armed height adds locked leaves the inert height does not have", - "XCHAIN_ESC locked leaf: delete-on-zero @regression NULL, empty and canonical zero are all \"no leaf\"", - "XCHAIN_ESC locked leaf: delete-on-zero @regression a fully filled order returns the tree to its pre-lock root", - "XCHAIN_ESC locked leaf: delete-on-zero @regression a negative total throws rather than committing (writer bug, not a state)", - "XCHAIN_ESC locked leaf: delete-on-zero @regression a nonzero total is amountLeaf, the same encoding the spendable leaf uses", - "XCHAIN_ESC locked leaf: inertness @regression a full rebuild with NO height argument keeps the v1 leaf set (fail closed)", - "XCHAIN_ESC locked leaf: inertness @regression an inert chain issues ZERO journal queries from the full rebuild", - "XCHAIN_ESC locked leaf: inertness @regression is inert on every chain, network and height EXCEPT the armed one", - "XCHAIN_ESC locked leaf: inertness @regression the ARMED height DOES read the journal (the gate really opened)", - "XCHAIN_ESC locked leaf: journal reads @regression MAX(id) runs over releases too: a released lock stays released", - "XCHAIN_ESC locked leaf: journal reads @regression an orphaned journal row reverts with no repair pass", - "XCHAIN_ESC locked leaf: journal reads @regression as-of-height reads serve the value the checkpoint committed", - "XCHAIN_ESC locked leaf: journal reads @regression incremental application equals a full rebuild of the same live set", - "XCHAIN_ESC locked leaf: journal reads @regression the touched set is per LOCKER, and only for blocks that changed a total", - "XCHAIN_ESC locked leaf: strict reads @regression a faulting live-set read THROWS rather than rebuilding balances_root with no locked leaves", - "XCHAIN_ESC locked leaf: strict reads @regression a faulting per-key read THROWS rather than DELETING the leaf (delete-on-zero)", - "XCHAIN_ESC locked leaf: strict reads @regression a faulting touched-key read THROWS rather than leaving the locked leaves stale", - "XCHAIN_ESC locked leaf: strict reads @regression every journal read goes through doQueryStrict, never doQuery", - "XCHAIN_ESC locked leaf: the \u00a77 shadow thread @regression no prior shadow root: full-builds through the caller callback (window start)", - "XCHAIN_ESC locked leaf: the \u00a77 shadow thread @regression null balanceUpdates (committed path full-recomputed) forces the shadow full build too", - "XCHAIN_ESC locked leaf: the \u00a77 shadow thread @regression the shadow value never reaches a committed column (source pin, both twins)", - "XCHAIN_ESC locked leaf: the \u00a77 shadow thread @regression threading equals a fresh build of the same leaf set (spendable + locked)" - ], "de57542d908be190": [ "coinTicker() + per-chain activation lookup normalization is idempotent on tickers and case-insensitive", "coinTicker() + per-chain activation lookup normalization maps full lowercase chain names to their ticker", @@ -2210,6 +3183,15 @@ "armed map v2: canonical value serialisation twin discipline is byte-identical to the xchain-indexer canonicaliser", "armed map v2: canonical value serialisation twin discipline requires nothing but crypto, so the same bytes serve both repos" ], + "e187211525c8a3de": [ + "ClientSync: bootstrap size wall a 429 is reported with the wait the source advertised", + "ClientSync: bootstrap size wall a generic transport failure still rotates and retries (no over-halting)", + "ClientSync: bootstrap size wall a rotating multi-source bootstrap stops at the first size wall", + "ClientSync: bootstrap size wall an oversized full snapshot halts durably instead of burning retry rounds", + "ClientSync: bootstrap size wall falls back to RateLimit-Reset when Retry-After is absent", + "ClientSync: bootstrap size wall persists the halt so the restart lands idle rather than back at the wall", + "ClientSync: bootstrap size wall the size wall has one definition, shared with the incremental fallback" + ], "e283c1eed8fe0836": [ "Unit: wireCodec (binary-safe row serialization) decodeValue does NOT decode a sentinel-shaped object with extra keys (collision guard)", "Unit: wireCodec (binary-safe row serialization) decodeValue does NOT decode when the tag value is not a string", @@ -2228,6 +3210,14 @@ "Unit: wireCodec (binary-safe row serialization) round-trip (encode \u2192 JSON \u2192 parse \u2192 decode) preserves an empty Buffer", "Unit: wireCodec (binary-safe row serialization) round-trip (encode \u2192 JSON \u2192 parse \u2192 decode) preserves arbitrary binary bytes including 0x00 and 0xFF" ], + "e2e378802d6bcdbf": [ + "02 Snapshot Performance Full snapshot export 100 blocks (baseline)", + "02 Snapshot Performance Full snapshot export 100 blocks with 10 actions each", + "02 Snapshot Performance Full snapshot export 500 blocks", + "02 Snapshot Performance Incremental snapshot export incremental from 10% (large delta)", + "02 Snapshot Performance Incremental snapshot export incremental from 50% (medium delta)", + "02 Snapshot Performance Incremental snapshot export incremental from 90% (small delta)" + ], "e34cac5673dfa0d1": [ "state-commitment flag-day activation @regression flags only the single activation boundary block", "state-commitment flag-day activation @regression gates on the local block_index per chain", @@ -2240,6 +3230,15 @@ "stateCommitment: persistent SMT == in-memory reference @regression matches the reference through updates and deletes (return-to-zero)", "stateCommitment: persistent SMT == in-memory reference @regression proofs from the persistent store verify (membership + non-membership)" ], + "e35b1c5b852ca0a8": [ + "consensus-constants (boundary) BTC stake-capability floors are a non-empty map returned by reference", + "consensus-constants (boundary) GAS_TICK / gasTickSymbol are the frozen XCHAIN symbol", + "consensus-constants (boundary) VALIDATOR_QUERY_LIMIT is a positive integer cap", + "consensus-constants (boundary) activationDelayBlocks is case-insensitive across ticker and full name", + "consensus-constants (boundary) activationDelayBlocks maps an unrecognized coin to undefined (hard misconfig)", + "consensus-constants (boundary) activationDelayBlocks maps null/undefined to the no-op null path", + "consensus-constants (boundary) activationDelayBlocks resolves a known coin to a non-negative integer" + ], "e3fcef2cb94f7253": [ "CORS_ORIGIN allowlist parsing getConfig() resolves CORS_ORIGIN, not the raw env string keeps the documented unset default of false (CORS disabled)", "CORS_ORIGIN allowlist parsing getConfig() resolves CORS_ORIGIN, not the raw env string turns a comma-separated value into an array before it can reach cors", @@ -2272,35 +3271,17 @@ "graceful shutdown resolveTimeoutMs prefers an explicit budget, then the env var, then the default", "graceful shutdown resolveTimeoutMs stays under Docker's 10s default stop grace" ], + "e6e589ac9f9ae7f9": [ + "E2E: Delta Synchronization 2.1 Client catches up after downtime syncs only missing blocks after client restart", + "E2E: Delta Synchronization 2.2 Large delta catch-up catches up 200 blocks via incremental snapshot", + "E2E: Delta Synchronization 2.3 Catch-up with diverse action types syncs blocks with different credit amounts", + "E2E: Delta Synchronization 2.4 No-op catch-up (already synced) handles catch-up when already at latest block" + ], "e76d24fca4e63da9": [ "follower: a missing prior roots row full-rebuilds, it does not thread from EMPTY @regression a present prior row still threads incrementally, unchanged", "follower: a missing prior roots row full-rebuilds, it does not thread from EMPTY @regression an empty touched set does not hide it: EMPTY was the exact old answer", "follower: a missing prior roots row full-rebuilds, it does not thread from EMPTY @regression commits the full-rebuild root when block-1 has no state_tree_roots row" ], - "e77b37f7efbcac18": [ - "stateCommitment: DbNodeStore.putMany SQL shape @regression an empty batch issues no statement at all", - "stateCommitment: DbNodeStore.putMany SQL shape @regression chunks a full-depth path so no single statement grows unbounded", - "stateCommitment: DbNodeStore.putMany SQL shape @regression duplicate hashes inside one batch are left to INSERT IGNORE, not pre-filtered away", - "stateCommitment: DbNodeStore.putMany SQL shape @regression writes one multi-row INSERT IGNORE with three bound params per row", - "stateCommitment: batched SMT node writes @regression DbNodeStore itself exposes putMany, so the real block path never takes the fallback", - "stateCommitment: batched SMT node writes @regression a key update costs ONE store write call, not one per tree level", - "stateCommitment: batched SMT node writes @regression a store with no putMany still gets the identical rows, one call per level", - "stateCommitment: batched SMT node writes @regression batched writes emit the SAME root and the SAME node set as per-node writes", - "stateCommitment: batched SMT node writes @regression deletes batch the same way and still return the tree to the empty root", - "stateCommitment: batched SMT node writes @regression the BTC stakes-subtree shape stays bounded: 49 keys cost 49 write calls, not 12,544", - "stateCommitment: batched SMT node writes @regression the batch is flushed before update() returns, so the next descend sees it", - "stateCommitment: stakes subtree rebuilds only on change @regression a CHANGED stake set rebuilds and moves the root", - "stateCommitment: stakes subtree rebuilds only on change @regression a GAP in block continuity rebuilds, even with an identical stake set", - "stateCommitment: stakes subtree rebuilds only on change @regression a RUN of unchanged blocks writes nothing after the first, not every other one", - "stateCommitment: stakes subtree rebuilds only on change @regression a cold start has no memo, so the first block after a restart rebuilds", - "stateCommitment: stakes subtree rebuilds only on change @regression a different chain or network never reads the other one's memo", - "stateCommitment: stakes subtree rebuilds only on change @regression a memoized root missing from the store rebuilds instead of committing it", - "stateCommitment: stakes subtree rebuilds only on change @regression an empty stake set is memoized without a store read that cannot succeed", - "stateCommitment: stakes subtree rebuilds only on change @regression an unchanged stake set on the next block writes NOTHING and returns the same root", - "stateCommitment: stakes subtree rebuilds only on change @regression re-parsing the SAME block index rebuilds rather than trusting a sibling memo", - "stateCommitment: stakes subtree rebuilds only on change @regression reordering the same stake entries still hits, because buildFull is order-independent", - "stateCommitment: stakes subtree rebuilds only on change @regression the memoized root is byte-identical to what buildFull would have returned" - ], "e78ca71e2270392c": [ "Boundary: Reorg Detection currentBlock = null (all blocks deleted): early return", "Boundary: Reorg Detection deep rollback (10 blocks): reorg at correct index", @@ -2312,19 +3293,50 @@ "Boundary: Reorg Detection one new block: no reorg", "Boundary: Reorg Detection same-height non-detection: no event when data changes at same block" ], - "e802cc9cf0d68125": [ - "armed map v2: manifest completeness over src/ every data export of every carrier is a manifest row", - "armed map v2: manifest completeness over src/ every manifest row names a carrier the scan found", - "armed map v2: manifest completeness over src/ every row resolves to the very value its carrier exports, with no refusal", - "armed map v2: manifest completeness over src/ keys are unique and every one is in the key grammar", - "armed map v2: manifest completeness over src/ sync has no ProtocolChanges table, so it owes no protocol_changes.changes rows", - "armed map v2: manifest completeness over src/ the carrier scan finds a real population, not a reassuring near-empty one" - ], "e89c73ba3a32ab98": [ "stakes_root validator-set parity: xchain-sync == xchain-indexer @regression BTC_STAKE_CAPABILITIES has the identical capability set as the indexer", "stakes_root validator-set parity: xchain-sync == xchain-indexer @regression VALIDATOR_QUERY_LIMIT matches the indexer", "stakes_root validator-set parity: xchain-sync == xchain-indexer @regression each capability MIN_STAKE floor matches the indexer" ], + "e8b11f7dc180370c": [ + "stateCommitment: DbNodeStore.putMany SQL shape @regression an empty batch issues no statement at all", + "stateCommitment: DbNodeStore.putMany SQL shape @regression chunks a full-depth path so no single statement grows unbounded", + "stateCommitment: DbNodeStore.putMany SQL shape @regression duplicate hashes inside one batch are left to INSERT IGNORE, not pre-filtered away", + "stateCommitment: DbNodeStore.putMany SQL shape @regression writes one multi-row INSERT IGNORE with three bound params per row" + ], + "e9198b686f505dd5": [ + "Integration: ServerPoller buildBlockPayload action-scoped probe agrees with the real fetch on which tables are empty", + "Integration: ServerPoller buildBlockPayload action-scoped probe cuts the per-table round-trips to the tables that actually have rows", + "Integration: ServerPoller buildBlockPayload action-scoped probe emits a byte-identical payload on a block that has rows", + "Integration: ServerPoller buildBlockPayload action-scoped probe emits a byte-identical payload on a block with no action-scoped rows", + "Integration: ServerPoller buildBlockPayload builds payload with correct structure from real DB", + "Integration: ServerPoller buildBlockPayload includes action-scoped rows (credits)", + "Integration: ServerPoller buildBlockPayload includes block-scoped table rows", + "Integration: ServerPoller buildBlockPayload includes index_addresses referenced by transactions", + "Integration: ServerPoller buildBlockPayload includes index_transactions referenced by block", + "Integration: ServerPoller buildBlockPayload includes transactions", + "Integration: ServerPoller buildBlockPayload returns null for non-existent block", + "Integration: ServerPoller poll detects and processes new blocks", + "Integration: ServerPoller poll detects reorg when block count decreases", + "Integration: ServerPoller poll does nothing when no new blocks", + "Integration: ServerPoller poll initializes lastPolledBlock on first poll", + "Integration: ServerPoller poll processes multiple sequential blocks", + "Integration: ServerPoller poll records each block in transparency log", + "Integration: ServerPoller poll returns early when no blocks in DB", + "Integration: ServerPoller updateStatus updates broadcaster status with real block data" + ], + "e962afbc1dd6ade5": [ + "ClientSync handleEvent runs the completeness sweep against the source that sent the status tick @regression" + ], + "eadfdc0dec6a56cd": [ + "SyncService startPollerForChain does not create duplicate pollers", + "SyncService startPollerForChain exits the process when the background poller crashes" + ], + "eb566567b1f2f3e3": [ + "E2E: Multi-Chain Synchronization 7.1 Two chains bootstrap independently bootstraps from shared source for both chains", + "E2E: Multi-Chain Synchronization 7.2 WebSocket subscriptions are chain-isolated receives events only for subscribed chain", + "E2E: Multi-Chain Synchronization 7.3 Reorg on one chain does not affect the other bitcoin reorg does not impact litecoin subscribers" + ], "ebef09fb184feed7": [ "/status replication freshness SYNC_REPLICA_MAX_LAG_S is configurable and defaults to 120s", "/status replication freshness client row carries the upstream verdict is unknown (null), never false, when no source reported the fields", @@ -2345,81 +3357,51 @@ "Boundary: INSERT Batch Size (100 rows) uses INSERT IGNORE for index tables at any batch size", "Boundary: INSERT Batch Size (100 rows) uses INSERT for non-index tables at any batch size" ], - "edf3154534f94dc7": [ - "SnapshotBuilder SnapshotStreamWriter (backpressure + client-abort) blocks until drain when the buffer is full (write() returns false)", - "SnapshotBuilder SnapshotStreamWriter (backpressure + client-abort) finish() detaches the disconnect handler and ends the stream", - "SnapshotBuilder SnapshotStreamWriter (backpressure + client-abort) rejects (aborted) and destroys gzip when the client disconnects mid-write", - "SnapshotBuilder SnapshotStreamWriter (backpressure + client-abort) resolves immediately when the buffer has room (write() returns true)", - "SnapshotBuilder _getOrderedTables excludes mempool_transactions (node-local, non-deterministic) like every other channel", - "SnapshotBuilder _getOrderedTables orders priority tables first, trailing tables last, middle alphabetically", - "SnapshotBuilder _getOrderedTables skips priority/trailing tables not in DB", - "SnapshotBuilder branch coverage _getOrderedTables drops operator-local tables and tolerates the uppercase TABLE_NAME variant", - "SnapshotBuilder branch coverage streamFullSnapshot aborts the whole snapshot on a per-table read error rather than omitting the table", - "SnapshotBuilder branch coverage streamFullSnapshot rolls back and rethrows when the snapshot read throws", - "SnapshotBuilder branch coverage streamFullSnapshot skips zero-count tables without failing the snapshot", - "SnapshotBuilder branch coverage streamFullSnapshot still returns quietly on a client-disconnect abort (not treated as a read error)", - "SnapshotBuilder branch coverage streamFullSnapshot writes empty hash headers when the hashRow lacks fields, comma-joins tables/rows, and serializes BigInt", - "SnapshotBuilder branch coverage streamIncrementalSnapshot decoder: emits X-Block-Hash and scopes skip/block/tx/full-dump tables correctly", - "SnapshotBuilder branch coverage streamIncrementalSnapshot fails closed (rejects + rolls back) on a transient per-table read error during incremental @regression", - "SnapshotBuilder branch coverage streamIncrementalSnapshot fails closed on a connection-drop (no errno) per-table read error during incremental @regression", - "SnapshotBuilder branch coverage streamIncrementalSnapshot indexer: emits empty hash headers, dumps full + action-scoped tables, and comma-joins them", - "SnapshotBuilder branch coverage streamIncrementalSnapshot indexer: scopes contract_emissions by block through the execution_index chain, not the action_index cursor @regression", - "SnapshotBuilder branch coverage streamIncrementalSnapshot indexer: skips middle tables when there is no firstActionIndex (no actions since the cursor)", - "SnapshotBuilder branch coverage streamIncrementalSnapshot indexer: still ships internal emissions when firstActionIndex is null @regression", - "SnapshotBuilder branch coverage streamIncrementalSnapshot rolls back and rethrows when the incremental read throws before streaming", - "SnapshotBuilder branch coverage streamIncrementalSnapshot ships matured cooldown refund credits when firstActionIndex is null (quiet window) @regression", - "SnapshotBuilder branch coverage streamIncrementalSnapshot swallows a per-table SCHEMA-GAP read error (errno 1146) during incremental", - "SnapshotBuilder paging-stream client-abort streamDispensers: swallows the abort and destroys gzip on client disconnect", - "SnapshotBuilder paging-stream client-abort streamTableRowsById: swallows the abort and destroys gzip on client disconnect", - "SnapshotBuilder snapshot concurrency cap cap is per Database instance, floored at 1 for tiny pools", - "SnapshotBuilder snapshot concurrency cap caps incremental snapshots on the same per-Database semaphore", - "SnapshotBuilder snapshot concurrency cap defaults the cap to poolSize - 2 (reserves poller + one short-read conn)", - "SnapshotBuilder snapshot concurrency cap falls back to per-dbType pool sizing, then DB_POOL_SIZE env", - "SnapshotBuilder snapshot concurrency cap honours MAX_CONCURRENT_SNAPSHOTS but clamps to [1, poolSize - 1]", - "SnapshotBuilder snapshot concurrency cap rejects a full snapshot with 503 SNAPSHOT_BUSY once the cap is reached, without opening a read view", - "SnapshotBuilder snapshot concurrency cap releases the slot when the stream throws", - "SnapshotBuilder snapshot concurrency cap tracks slots independently per Database (one chain cannot starve another)", - "SnapshotBuilder streamDispensers first page (no cursor) selects the full table ordered by the composite PK", - "SnapshotBuilder streamDispensers honours a legacy cursor within the same single response and never reports more", - "SnapshotBuilder streamDispensers rejects a non-decoder dbType with 400", - "SnapshotBuilder streamDispensers rejects instead of shipping an empty dump when the source read fails @regression", - "SnapshotBuilder streamDispensers rejects on a failed read in the cursor branch too @regression", - "SnapshotBuilder streamFullSnapshot client-abort releases the read view and stops when the client disconnects mid-stream", - "SnapshotBuilder streamFullSnapshot emits every row of a keyless table exactly once in a single ordered pass (no offset re-paging)", - "SnapshotBuilder streamFullSnapshot returns 404 when no blocks in database", - "SnapshotBuilder streamFullSnapshot sets correct response headers", - "SnapshotBuilder streamFullSnapshot skips tables with 0 rows", - "SnapshotBuilder streamFullSnapshot streams valid gzip JSON for tables with data", - "SnapshotBuilder streamIncrementalSnapshot decoder: re-dumps the events table in full on incremental", - "SnapshotBuilder streamIncrementalSnapshot indexer: re-dumps index_* lookup tables in full on incremental", - "SnapshotBuilder streamIncrementalSnapshot indexer: re-dumps the events audit log in full on incremental, paged by id", - "SnapshotBuilder streamIncrementalSnapshot lookup paging pages a full-dump lookup table by id cursor instead of one unbounded SELECT *", - "SnapshotBuilder streamIncrementalSnapshot returns 404 when no blocks after sinceBlock", - "SnapshotBuilder streamIncrementalSnapshot returns 404 when no blocks at all", - "SnapshotBuilder streamIncrementalSnapshot skipLookups omits the .index lookup tables but keeps block-scoped data", - "SnapshotBuilder streamIncrementalSnapshot snapshot-replication tables full-dumps indexer pubkeys instead of action-scoping it into errno 1054", - "SnapshotBuilder streamIncrementalSnapshot streams incremental data with since_block field", - "SnapshotBuilder streamTableRowsById clamps an oversized limit to the ceiling", - "SnapshotBuilder streamTableRowsById decoder: pages the pubkeys table by its surrogate monotonic id cursor", - "SnapshotBuilder streamTableRowsById queries id > after_id ORDER BY id LIMIT, and sets has_more when a full page returns", - "SnapshotBuilder streamTableRowsById rejects a non-pageable table with 400", - "SnapshotBuilder streamTableRowsById streams an id-ordered page with max_id and has_more=false when short", - "SnapshotBuilder transactional boundary full: commits (releases) the snapshot even on the 404 empty-db path", - "SnapshotBuilder transactional boundary full: opens read snapshot before reading the block anchor", - "SnapshotBuilder transactional boundary full: rolls back the snapshot if a read throws before streaming", - "SnapshotBuilder transactional boundary incremental: commits (releases) the snapshot on the 404 path", - "SnapshotBuilder transactional boundary incremental: opens read snapshot before reading the block anchor" + "ec77114beed6a450": [ + "Integration: Client Live Sync duplicate block handling skips already-applied block without error", + "Integration: Client Live Sync live block applied via WebSocket applies a single block received via WS to replica", + "Integration: Client Live Sync live block applied via WebSocket applies multiple sequential blocks" ], - "ee110e57ac665f06": [ - "ClientSync._oraclePublishSetAt uses the as-of reconstruction (#4927) calls getStakeWeightsByCapabilityAsOf, not the live getStakeWeightsByCapability", - "Database.getStakeWeightsByCapabilityAsOf (#4927) REFUSES a null weight rather than defaulting it to \"0\"", - "Database.getStakeWeightsByCapabilityAsOf (#4927) adds back post-snapshot stakes slash debits in the weight subquery", - "Database.getStakeWeightsByCapabilityAsOf (#4927) binds the add-back snapshot block FIRST, then the base arg sequence, then LIMIT", - "Database.getStakeWeightsByCapabilityAsOf (#4927) does not reference _stakeWeightsSql (keeps the drift-guarded twin untouched)", - "Database.getStakeWeightsByCapabilityAsOf (#4927) maps rows to {pubkey, source, weight}", - "Database.getStakeWeightsByCapabilityAsOf (#4927) passes minStake through to the HAVING floor as a string", - "Database.getStakeWeightsByCapabilityAsOf (#4927) placeholder count equals the bound-arg count (arg-order drift guard)", - "Database.getStakeWeightsByCapabilityAsOf (#4927) returns [] when the valid status id cannot be resolved (no query run)" + "ece551d681b05cc7": [ + "E2E: Reorg Propagation 3.1 Simple reorg (3 blocks) propagates reorg and new blocks correctly", + "E2E: Reorg Propagation 3.2 Reorg with balance impact recalculates balances correctly after reorg", + "E2E: Reorg Propagation 3.3 Deep reorg (10 blocks) handles deep rollback and re-sync", + "E2E: Reorg Propagation 3.4 Reorg to shorter chain rolls back without immediate replacement blocks", + "E2E: Reorg Propagation 3.5 Consecutive reorgs handles two rapid reorgs without corruption" + ], + "ed046892e95da65f": [ + "contract_state_root: incremental equals full build @regression key insertion order does not change the root (the SMT is key-addressed)", + "contract_state_root: shadow-compute window @regression ARMED WINS: a height that is both shadowing and armed shadows nothing", + "contract_state_root: shadow-compute window @regression ships inert: nothing shadows on any chain, network or height" + ], + "edeb00b6254cb702": [ + "ClientSync stop sets running to false" + ], + "ee22ef37c7d06c2b": [ + "assembleStateRoot: reserved-slot carrier is inert @regression explicitly EMPTY reserved sub-roots are byte-identical to the two-argument form", + "assembleStateRoot: reserved-slot carrier is inert @regression ignores keys that are not reserved slot names", + "assembleStateRoot: reserved-slot carrier is inert @regression null / undefined / empty extraSubRoots are byte-identical to the two-argument form", + "assembleStateRoot: reserved-slot carrier is inert @regression still matches merkle.stateRoot for the two v1 sub-roots", + "assembleStateRoot: reserved-slot carrier is inert @regression the ARMED chain commits a DIFFERENT root, which is the whole point of arming", + "assembleStateRoot: reserved-slot carrier is inert @regression the gated block-path value is null on every INERT chain, so its root is the v1 root", + "assembleStateRoot: reserved-slot carrier is real @regression a populated reserved sub-root changes state_root", + "assembleStateRoot: reserved-slot carrier is real @regression an EMPTY reserved slot still proves as EMPTY_SMT_ROOT against the v1 root", + "assembleStateRoot: reserved-slot carrier is real @regression assembleStateRoot agrees with merkle.stateRoot when slots are populated", + "assembleStateRoot: reserved-slot carrier is real @regression each reserved slot occupies its own leaf position", + "assembleStateRoot: reserved-slot carrier is real @regression stateRootProof verifies a reserved sub-root against the assembled root", + "state_root reserved sub-trees: gateSubRoots @regression a bare-network key arms nothing (coin-qualified keys are the only lookup)", + "state_root reserved sub-trees: gateSubRoots @regression an armed escrow leaf flips the derived version to 2 (leaf-set changes are never version-invisible)" + ], + "eebf1ea70711d38c": [ + "E2E: Error Handling & Recovery 4.3 Server restart (client reconnects and catches up) recovers after server stops and restarts", + "E2E: Error Handling & Recovery 4.4 Client restart after source advances catches up to current block after restart", + "E2E: Error Handling & Recovery 4.6 Hub unavailable at startup (server waits) server handles missing hub gracefully", + "E2E: Error Handling & Recovery 4.7 Duplicate blocks do not cause errors handles receiving a block that already exists", + "E2E: Error Handling & Recovery 4.8 Server poll error does not crash continues polling after a transient error" + ], + "eee91ecc715fb032": [ + "ClientSync: VERIFY_RECOMPUTE=false is declared unsafe @regression stays quiet when recompute is enabled", + "ClientSync: VERIFY_RECOMPUTE=false is declared unsafe @regression warns UNSAFE at construction when explicitly disabled" ], "ef4deb6bc7390bd3": [ "HashVerifier compareBlockHashes detects all three fields mismatched", @@ -2433,18 +3415,8 @@ "HashVerifier verifyChainContinuity returns valid when prevBlockIndex is null (bootstrap)", "HashVerifier verifyChainContinuity returns valid when prevHashes is null" ], - "efb438dc7752318a": [ - "vendored checkpoint verifier (twin conformance) @regression a garbage-then-valid duplicate for one signer still PASSES (seen marked after verify)", - "vendored checkpoint verifier (twin conformance) @regression an empty validator set can never verify", - "vendored checkpoint verifier (twin conformance) @regression canonicalCheckpoint matches the ACTIVE SPV-root spec byte-for-byte (EQUIV-wrapped, roots committed)", - "vendored checkpoint verifier (twin conformance) @regression canonicalCheckpoint matches the ANCHOR spec byte-for-byte (SDK-pinned golden vector)", - "vendored checkpoint verifier (twin conformance) @regression rejects a checkpoint whose signer is not in the pinned set", - "vendored checkpoint verifier (twin conformance) @regression rejects a checkpoint with a tampered field (signature no longer matches the canonical)", - "vendored checkpoint verifier (twin conformance) @regression src/checkpoint.js is code-identical to the xchain-sdk copy (comments excepted)", - "vendored checkpoint verifier (twin conformance) @regression src/checkpoint_commitment_activation.js is code-identical to the xchain-sdk copy (comments excepted)", - "vendored checkpoint verifier (twin conformance) @regression src/equivocation_header.js is code-identical to the xchain-sdk copy (comments excepted)", - "vendored checkpoint verifier (twin conformance) @regression src/stake_weighted_quorum.js is code-identical to the xchain-sdk copy (comments excepted)", - "vendored checkpoint verifier (twin conformance) @regression verifies a real Ed25519 quorum-signed checkpoint against its pinned set" + "f1150c948244069d": [ + "Integration: REST API GET /schema/:dbType/:chain/:network returns table DDLs" ], "f15a3c001afd798e": [ "decoder table classification (schema exhaustiveness) @regression classifies every xchain-decoder/src/sql table as replicated or excluded", @@ -2452,18 +3424,41 @@ "decoder table classification (schema exhaustiveness) @regression keeps every excluded decoder table clear-protected on full-snapshot apply", "decoder table classification (schema exhaustiveness) @regression never lists a decoder table as both replicated and excluded" ], - "f1a54aa20d85cdc2": [ - "Database.addMissingColumns is a no-op when the replica already has every source column", - "Database.addMissingColumns issues ALTER TABLE ADD COLUMN for each column the replica lacks", - "Database.addMissingColumns returns 0 for an unparseable DDL", - "Database.addMissingColumns skips (does not abort) a column whose definition cannot be parsed", - "Database.addMissingColumns: AUTO_INCREMENT key clause adds no key clause for an ordinary column, including one whose COMMENT says auto_increment", - "Database.addMissingColumns: AUTO_INCREMENT key clause appends the source UNIQUE key so the ALTER is not refused with errno 1075", - "Database.addMissingColumns: AUTO_INCREMENT key clause emits an UNQUALIFIED ALTER against the pool default database, so Replicate_Do_DB forwards it", - "Database.addMissingColumns: AUTO_INCREMENT key clause falls back to a UNIQUE key when the replica already has a different primary key", - "Database.addMissingColumns: AUTO_INCREMENT key clause reports a refused ALTER as a failure and never logs \"Added column\"", - "Database.addMissingColumns: AUTO_INCREMENT key clause reproduces a source PRIMARY KEY when the replica has no primary key", - "Database.addMissingColumns: AUTO_INCREMENT key clause synthesises a UNIQUE key when the source declares no single-column key on the auto column", + "f2f7e767a0317d4c": [ + "SnapshotBuilder streamDispensers first page (no cursor) selects the full table ordered by the composite PK", + "SnapshotBuilder streamDispensers honours a legacy cursor within the same single response and never reports more", + "SnapshotBuilder streamDispensers rejects a non-decoder dbType with 400", + "SnapshotBuilder streamDispensers rejects instead of shipping an empty dump when the source read fails @regression", + "SnapshotBuilder streamDispensers rejects on a failed read in the cursor branch too @regression" + ], + "f40b8e55e94cbb45": [ + "E2E: Cross-Source Hash Verification 5.1 Two matching sources (normal operation) syncs when both sources agree on hashes", + "E2E: Cross-Source Hash Verification 5.3 Secondary source unavailable (timeout fallback) applies from primary after timeout when secondary is unavailable", + "E2E: Cross-Source Hash Verification 5.4 Verification disabled (immediate apply) syncs without waiting for second source when verification is off" + ], + "f45334c14832a872": [ + "validation extractColumnNames does not pick up the table name or constraint identifiers", + "validation extractColumnNames extracts every column name in order", + "validation extractColumnNames returns [] for non-string input" + ], + "f4ec21668243211b": [ + "sync-owned table classification (registry exhaustiveness) classifies every src/sql table in at least one registry", + "sync-owned table classification (registry exhaustiveness) classifies sync_state (created ad hoc by db.js, no .sql file)", + "sync-owned table classification (registry exhaustiveness) keeps merkle_reorgs out of the streamed set but in the clearable set", + "sync-owned table classification (registry exhaustiveness) never puts a table in both snapshot-builder sets (contradictory clear semantics)" + ], + "f4f95d87d6f86904": [ + "Integration: the follower at an armed height, and a reorg across it a reorg across the armed height reverts it, and re-advancing reproduces it exactly", + "Integration: the follower at an armed height, and a reorg across it a snapshot bootstrap AT the armed height commits the same roots as threading across it", + "Integration: the follower at an armed height, and a reorg across it commits the locked leaf inside balances_root at the armed height", + "Integration: the follower at an armed height, and a reorg across it commits the slot at the armed height, and the stored state_root reassembles from it", + "Integration: the follower at an armed height, and a reorg across it leaves both activation maps exactly as it found them", + "Integration: the follower at an armed height, and a reorg across it reports version 2 at the armed height and 1 immediately below it" + ], + "f5a2f59de279c2b5": [ + "E2E: Disconnect/Resume Parity 10.2 Reorg while disconnected (June 2026 production scenario) a replica holding orphaned blocks must not silently follow the new chain; a re-seed converges it" + ], + "f610ec2582be7e3b": [ "Database.ensureReplicatedColumns: nullability relaxation adds state_tree_roots.contract_state_root on an aged replica that already has the table", "Database.ensureReplicatedColumns: nullability relaxation does nothing on a decoder replica (early return, no queries)", "Database.ensureReplicatedColumns: nullability relaxation is a no-op when contract_emissions / the column is absent on the replica", @@ -2472,131 +3467,684 @@ "Database.ensureReplicatedColumns: nullability relaxation relaxes contract_emissions.action_index NOT NULL -> NULL when the replica column is NOT NULL", "Database.ensureReplicatedColumns: nullability relaxation the added definition matches src/sql/state_tree_roots.sql (one column, two declarations)" ], - "f4ec21668243211b": [ - "sync-owned table classification (registry exhaustiveness) classifies every src/sql table in at least one registry", - "sync-owned table classification (registry exhaustiveness) classifies sync_state (created ad hoc by db.js, no .sql file)", - "sync-owned table classification (registry exhaustiveness) keeps merkle_reorgs out of the streamed set but in the clearable set", - "sync-owned table classification (registry exhaustiveness) never puts a table in both snapshot-builder sets (contradictory clear semantics)" + "f904093dd63c32cc": [ + "contract_state_root: shadow-compute window @regression a shadow value NEVER reaches state_root", + "contract_state_root: shadow-compute window @regression the arming block full-builds and does NOT inherit the shadow value", + "contract_state_root: shadow-compute window @regression the shadow derives a real root and threads through its OWN column" + ], + "f97b150a709be189": [ + "ClientApplier in-place updated-rows apply applyBlock UPSERTs payload.updated_rows for surviving rows", + "ClientApplier in-place updated-rows apply maybeRederiveEscrow runs the escrow re-derive only when an escrow-relevant table is present", + "ClientApplier in-place updated-rows apply upsertRows emits INSERT ... ON DUPLICATE KEY UPDATE writing every column", + "ClientApplier in-place updated-rows apply upsertRows throws on an invalid table identifier without querying (fail closed)", + "updatedRows.collectUpdatedRows carries a DELEGATE v1 signing-key rotation on surviving stake AND cooldown rows", + "updatedRows.collectUpdatedRows carries the stamped ATTEST v5 batch head on the block its completing v6 chunk landed in", + "updatedRows.collectUpdatedRows dedups a row reached by two classes (deactivated AND slashed) by action_index", + "updatedRows.collectUpdatedRows detects SLASH amount cuts via the debit log join and v0 request_status flips", + "updatedRows.collectUpdatedRows detects deactivation stamps by value-threshold [from+delay, to+delay]", + "updatedRows.collectUpdatedRows emits the v0 request flip and the v5 batch head as separate attests rows, deduped by action_index", + "updatedRows.collectUpdatedRows keys the VOTE poll class on resolved_block OR a fired deferred-callback due block (one scan)", + "updatedRows.collectUpdatedRows refreshes surviving tokens rows for ticks touched by ledger changes in the window", + "updatedRows.collectUpdatedRows rethrows a non-schema error from the attest batch-head class (never a silent drop)", + "updatedRows.collectUpdatedRows skips the attest batch-head class on a pre-batch-rail schema instead of throwing", + "updatedRows.collectUpdatedRows skips the deactivation_block class entirely when activationDelay is null", + "updatedRows.collectUpdatedRows uses target_table to separate contract_stakes vs contract_unstakes" + ], + "f9851634c56991cb": [ + "ServerPoller poll snapshot pinning (H-P2) never streams past the snapshot tip when it sits behind the outer read", + "ServerPoller poll snapshot pinning (H-P2) pins the forward batch to one read snapshot and threads it through every payload read", + "ServerPoller poll snapshot pinning (H-P2) releases the snapshot even when payload building throws", + "ServerPoller poll snapshot pinning (H-P2) streams to the snapshot tip when a block landed between the outer read and the snapshot open" + ], + "f9be87c45e7f293b": [ + "E2E: Disconnect/Resume Parity 10.3 Torn bootstrap state re-bootstrapping over a torn replica converges byte-identically" + ], + "fb2faaff7e9ed70f": [ + "Tier 2 - ClientRollback @tier2 rollback balance DELETE comes before balance INSERT", + "Tier 2 - ClientRollback @tier2 rollback never throws for any valid block_index", + "Tier 2 - ClientRollback @tier2 rollback schema-gap (missing table/column) errors do not abort the operation", + "Tier 2 - ClientRollback @tier2 rollback sync_meta DELETE uses correct block_index argument", + "Tier 2 - ClientRollback @tier2 rollback transaction is always committed or rolled back, never leaked", + "Tier 2 - ClientRollback @tier2 rollback when firstActionIndex is null, action-scoped DELETEs use no action_index filter" + ], + "fc2e4e6f74912b6b": [ + "ServerPoller poll detects a net-forward reorg via a changed same-height hash", + "ServerPoller poll detects reorg and broadcasts reorg event", + "ServerPoller poll does not attempt a transparency prune on reorg for the decoder (no log)", + "ServerPoller poll does not flag a net-forward reorg when the same-height hash is unchanged", + "ServerPoller poll does nothing when currentBlock equals lastPolledBlock", + "ServerPoller poll initializes lastPolledBlock on first poll", + "ServerPoller poll limits to 100 blocks per poll", + "ServerPoller poll processes multiple sequential blocks", + "ServerPoller poll processes new blocks when currentBlock > lastPolledBlock", + "ServerPoller poll prunes the source transparency log on reorg (to currentBlock + 1)", + "ServerPoller poll re-evaluates the replica verdict on idle polls", + "ServerPoller poll resolves a multi-block net-forward reorg to the true fork in a single poll", + "ServerPoller poll returns early when no blocks in DB", + "ServerPoller table lists has action-scoped tables", + "ServerPoller table lists has block-scoped tables", + "ServerPoller table lists has index tables" + ], + "fc42c2acf198daed": [ + "E2E: Interleaved disconnect/reorg/restart parity (property) randomized schedule run 1 ends byte-identical or legitimately halted", + "E2E: Interleaved disconnect/reorg/restart parity (property) randomized schedule run 2 ends byte-identical or legitimately halted" + ], + "fdfe268c9e47e92f": [ + "BlockBroadcaster broadcast does not send to other chain/network", + "BlockBroadcaster broadcast does nothing when no subscribers", + "BlockBroadcaster broadcast encodes binary columns in the updated_rows channel (same wire codec as data)", + "BlockBroadcaster broadcast infra-only subscriber receives only infra tables, filtered from event.data", + "BlockBroadcaster broadcast infra-only subscriber receives the infra subset of updated_rows", + "BlockBroadcaster broadcast infra-only subscriber with no matching infra tables gets an empty data set (not the full block)", + "BlockBroadcaster broadcast sends to all subscribers of a chain/network" ] }, "scripts": { "test": { - "fileCount": 109, - "titleCount": 2209, + "fileCount": 248, + "titleCount": 2270, "files": { - "test/unit/BlockBroadcaster.test.js": "75fa9b19165be9cf", - "test/unit/BlockHasher.test.js": "b6f88326a1ba0d27", - "test/unit/ClientApplier.strictIgnoreCheck.test.js": "76d8fd79030c9638", - "test/unit/ClientApplier.test.js": "0acdc71d34c76fe1", - "test/unit/ClientRollback.test.js": "71d730e75a4de5ea", - "test/unit/ClientSync.checkpointQuorum.test.js": "8b6cb617a8c580f3", - "test/unit/ClientSync.halt.test.js": "631fe6ded689ba09", - "test/unit/ClientSync.io.test.js": "822af834cce5f18d", - "test/unit/ClientSync.schemaApply.test.js": "3b2f993a46d5c309", - "test/unit/ClientSync.sourceQuorum.test.js": "4d1ce9c4b6023937", - "test/unit/ClientSync.test.js": "9cd5c17223db456a", - "test/unit/ClientSync.tipHashRefresh.test.js": "283afce58127f133", - "test/unit/ClientSync.trainActivation.test.js": "83fe31113184d5b3", - "test/unit/ConsensusPrimitiveConformance.test.js": "091ee0965b4ff600", - "test/unit/HashVerifier.test.js": "ef4deb6bc7390bd3", - "test/unit/HubClient.test.js": "532c53b5adb93aa6", - "test/unit/MerkleTree.test.js": "0c488b6b47a588af", - "test/unit/ServerPoller.actionScopedProbe.test.js": "d7ac1268f904a175", - "test/unit/ServerPoller.test.js": "1fdd9eb5a4de22db", - "test/unit/SnapshotBuilder.test.js": "edf3154534f94dc7", - "test/unit/StateHash.test.js": "c54bb56b0f6fae1f", - "test/unit/SyncService.test.js": "b7040d6dffe594c1", - "test/unit/TransparencyLog.readonly.test.js": "438f210bee5c5290", - "test/unit/TransparencyLog.retention.test.js": "77025ae7ee6bc534", - "test/unit/TransparencyLog.test.js": "09cd28d5ace1d077", - "test/unit/armedMapFingerprint.test.js": "1d2c13f91db9640e", - "test/unit/balance-helpers.test.js": "b146f330faa567f9", - "test/unit/blockhash-conformance-twin.test.js": "6f8cd171d7d29aa7", - "test/unit/boundaries/batch-insert.test.js": "ec173aca8005e2db", - "test/unit/boundaries/block-index.test.js": "3c56690bfa37c105", - "test/unit/boundaries/circuit-breaker.test.js": "364d8f8918f3b7b9", - "test/unit/boundaries/config-parsing.test.js": "48d7bc42ba69d0ed", - "test/unit/boundaries/hash-continuity.test.js": "a88f7793e0424865", - "test/unit/boundaries/hub-port-parsing.test.js": "b34e13bb2c06de34", - "test/unit/boundaries/poll-limit.test.js": "01f9d7edc3706d8a", - "test/unit/boundaries/reorg-detection.test.js": "e78ca71e2270392c", - "test/unit/boundaries/rollback-scope.test.js": "583bc57c330cae05", - "test/unit/boundaries/source-array.test.js": "0db309d4b8251770", - "test/unit/boundaries/transparency-page.test.js": "9c0fc1385ec3e33c", - "test/unit/boundaries/websocket-limits.test.js": "8a703039473bdaa7", - "test/unit/checkpoint.twin.test.js": "efb438dc7752318a", - "test/unit/checkpointQuorumFlagDay.test.js": "7a4688817472b50c", - "test/unit/checkpoint_commitment_activation.test.js": "7ce539894822d70a", + "test/unit/balance_helpers.test.js": "b146f330faa567f9", + "test/unit/block_broadcaster.test.js": "8dd046e550af23cc", + "test/unit/block_broadcaster.test/01_remove_subscription.test.js": "56ea43b3d3b87ccd", + "test/unit/block_broadcaster.test/02_broadcast.test.js": "fdfe268c9e47e92f", + "test/unit/block_broadcaster.test/03_broadcast_status.test.js": "a3a695ffa9cdefe5", + "test/unit/block_broadcaster.test/04_get_status_freshness_expiry.test.js": "45fff32ccaa4f955", + "test/unit/block_broadcaster.test/05_send.test.js": "ca3ce40121d57267", + "test/unit/block_broadcaster.test/06_applied_block_tracking.test.js": "1f144263f64d3946", + "test/unit/block_broadcaster.test/07_get_subscriber_count.test.js": "5751017b882d5474", + "test/unit/block_broadcaster.test/08_get_validator_heartbeats.test.js": "6362e6d5b508b99d", + "test/unit/block_broadcaster.test/09_get_validator_heartbeats_with_an_expected_validator_roster.test.js": "27948aa1cde1b70e", + "test/unit/block_broadcaster.test/10_evict_stale_validators.test.js": "3db5faf2fec0a01f", + "test/unit/block_hasher.test.js": "b6f88326a1ba0d27", + "test/unit/blockhash_conformance_twin.test.js": "6f8cd171d7d29aa7", + "test/unit/boundaries/batch_insert.test.js": "ec173aca8005e2db", + "test/unit/boundaries/block_index.test.js": "3c56690bfa37c105", + "test/unit/boundaries/circuit_breaker.test.js": "364d8f8918f3b7b9", + "test/unit/boundaries/config_parsing.test.js": "48d7bc42ba69d0ed", + "test/unit/boundaries/hash_continuity.test.js": "a88f7793e0424865", + "test/unit/boundaries/hub_port_parsing.test.js": "2831ab2c30bba1b2", + "test/unit/boundaries/poll_limit.test.js": "01f9d7edc3706d8a", + "test/unit/boundaries/reorg_detection.test.js": "e78ca71e2270392c", + "test/unit/boundaries/rollback_scope.test.js": "583bc57c330cae05", + "test/unit/boundaries/source_array.test.js": "a5edff5ddc7a7030", + "test/unit/boundaries/transparency_page.test.js": "9c0fc1385ec3e33c", + "test/unit/boundaries/websocket_limits.test.js": "8a703039473bdaa7", + "test/unit/checkpoint_quorum_flag_day.test.js": "7a4688817472b50c", + "test/unit/checkpoint_twin.test.js": "aed79f98d38bbde3", + "test/unit/client_applier.test.js": "cf73b1d25cf81b8c", + "test/unit/client_applier.test/01_apply_full_snapshot.test.js": "b2c127c405cfa5f5", + "test/unit/client_applier.test/02_apply_incremental_snapshot.test.js": "4647d4059a28745e", + "test/unit/client_applier.test/03_insert_rows.test.js": "93d6210945bb30dd", + "test/unit/client_applier.test/04_apply_dispensers_replace.test.js": "932531f1175e9a43", + "test/unit/client_applier.test/05_anchor_actions_bundle_sections.test.js": "07d974594667f5bb", + "test/unit/client_applier_strict_ignore_check.test.js": "76d8fd79030c9638", + "test/unit/client_rollback.test.js": "a86e3201d3a619c6", + "test/unit/client_rollback.test/01_rollback.test.js": "53f2c023f224ee8b", + "test/unit/client_rollback.test/02_rollback.test.js": "677fde3e236166c4", + "test/unit/client_rollback.test/03_rollback.test.js": "289986a69cb8db56", + "test/unit/client_rollback.test/04_pair_scoped_markets_rollback_idx_2_mirror.test.js": "9743546a34b05c9f", + "test/unit/client_rollback.test/05_balance_rebuild_error_handling.test.js": "cefc03d7e7861167", + "test/unit/client_rollback.test/06_rollback_decoder.test.js": "b2eb6ba6aa6d5bb2", + "test/unit/client_sync.test.js": "a5dcb3dfab180b59", + "test/unit/client_sync.test/01_warn_trust_posture.test.js": "9f32bf1a82b5f6ab", + "test/unit/client_sync.test/02_is_source_height_stale.test.js": "5d10b0ffea8843e3", + "test/unit/client_sync.test/03_log_gap_throttling.test.js": "c01052b400b95da9", + "test/unit/client_sync.test/04_start.test.js": "6825350ea939c1f3", + "test/unit/client_sync.test/05_bootstrap_failure_gating_empty_replica_defect.test.js": "c19f60997c7483e1", + "test/unit/client_sync.test/06_handle_event.test.js": "447987fa6855b9be", + "test/unit/client_sync.test/07_maybe_verify_completeness.test.js": "805df1c0d5571b8d", + "test/unit/client_sync.test/08_persistent_replica_gaps.test.js": "6fe6527e42a197a6", + "test/unit/client_sync.test/09_handle_block.test.js": "7d9682f3a69106c6", + "test/unit/client_sync.test/10_apply_block_event.test.js": "99d874997e2b72e1", + "test/unit/client_sync.test/11_heal_schema_if_stale.test.js": "ca3ef17f876157b0", + "test/unit/client_sync.test/12_run_incremental_catch_up_schema_self_heal.test.js": "606dc37fb546bda6", + "test/unit/client_sync.test/13_handle_reorg.test.js": "1038be37b3b01cb3", + "test/unit/client_sync.test/14_constructor_sync_mode_chain_infra_only_vs_the_halting_verification_gates.test.js": "9e08b97fcd02776a", + "test/unit/client_sync.test/15_stop.test.js": "edeb00b6254cb702", + "test/unit/client_sync.test/16_verify_table_counts_replica_completeness.test.js": "169ecc74d07da9cf", + "test/unit/client_sync.test/17_decoder_bootstrap_completeness.test.js": "4ee867ce8010316d", + "test/unit/client_sync.test/18_should_reconcile_dispensers_decoder_resume_cadence.test.js": "0ddb81e3688155bc", + "test/unit/client_sync_checkpoint_quorum.test.js": "b57e7bf0add0a957", + "test/unit/client_sync_checkpoint_quorum.test/01_checkpoint_quorum_rotation_following.test.js": "5fd53912b63d1fe2", "test/unit/client_sync_dispenser_reconcile_tick.test.js": "dcf4bd51a912a4e0", - "test/unit/coin-ticker-activation.test.js": "de57542d908be190", - "test/unit/coins-conformance.test.js": "2442df610ebb6911", - "test/unit/config.test.js": "b2efd648f4757794", + "test/unit/client_sync_halt.test.js": "890c1afd26223048", + "test/unit/client_sync_halt.test/01_independent_recompute_halt.test.js": "86523982ea831a05", + "test/unit/client_sync_halt.test/02_bulk_range_boundary_recompute.test.js": "2de09f9ac8510fc7", + "test/unit/client_sync_halt.test/03_state_hash_apply_time_integrity_halt.test.js": "c887799f86d69a43", + "test/unit/client_sync_halt.test/04_verify_recompute_false_is_declared_unsafe.test.js": "eee91ecc715fb032", + "test/unit/client_sync_io.test.js": "637056de9db4317f", + "test/unit/client_sync_io.test/01_bootstrap_size_wall.test.js": "e187211525c8a3de", + "test/unit/client_sync_io.test/02_bootstrap_from_height.test.js": "549430c7ecacfc94", + "test/unit/client_sync_io.test/03_sync_lookup_tables_paged.test.js": "19b6bdb857cf7156", + "test/unit/client_sync_io.test/04_truncated_catch_up.test.js": "db43ccc2db666f97", + "test/unit/client_sync_io.test/05_oversized_catch_up_fallback_routes_by_truncation.test.js": "5d1de29605d15857", + "test/unit/client_sync_io.test/06_decoder_completeness_check_on_a_truncated_replica.test.js": "5cb20fdb5738741b", + "test/unit/client_sync_io.test/07_indexer_head_fork_re_delivery.test.js": "0c06733c3bf59e5e", + "test/unit/client_sync_io.test/08_verify_recompute_join_block_skip.test.js": "87e2f6a904c7a19a", + "test/unit/client_sync_io.test/09_run_incremental_catch_up.test.js": "0351fed12642c8a1", + "test/unit/client_sync_io.test/10_incremental_catch_up_coalescing.test.js": "5ff54077cc3ba86f", + "test/unit/client_sync_io.test/11_strict_cross_source_gate_survives_catch_up_m_22.test.js": "be748fea997da5e8", + "test/unit/client_sync_io.test/12_verify_against_source.test.js": "6e98846a4e3b9709", + "test/unit/client_sync_io.test/13_verify_decoder_completeness_catch.test.js": "665052ac9fa042e3", + "test/unit/client_sync_io.test/14_stop.test.js": "8018794f66fac00f", + "test/unit/client_sync_io.test/15_heartbeat.test.js": "2de415b648901dff", + "test/unit/client_sync_io.test/16_connect_web_socket.test.js": "81b2c5034f4c92dd", + "test/unit/client_sync_io.test/17_handle_event_last_known_server_block_branches.test.js": "2c00f2c184ea8958", + "test/unit/client_sync_io.test/18_misc_branch_coverage.test.js": "5ccec02617fb694b", + "test/unit/client_sync_io.test/19_small_branches.test.js": "3771857a17674d3d", + "test/unit/client_sync_io.test/20_lookup_hole_repair_and_count_check_scoping_regression.test.js": "20341c70321425c4", + "test/unit/client_sync_schema_apply.test.js": "b6ab840e3149d748", + "test/unit/client_sync_source_quorum.test.js": "4d1ce9c4b6023937", + "test/unit/client_sync_tip_hash_refresh.test.js": "283afce58127f133", + "test/unit/client_sync_train_activation.test.js": "83fe31113184d5b3", + "test/unit/coin_ticker_activation.test.js": "de57542d908be190", + "test/unit/coins_conformance.test.js": "2442df610ebb6911", + "test/unit/config.test.js": "5af0bd1c2d576260", "test/unit/consensus/armed_map/canonical.test.js": "e03eeb17175d1023", - "test/unit/consensus/armed_map/completeness.test.js": "e802cc9cf0d68125", - "test/unit/consensus/armed_map/falsification.test.js": "042207350fe3ef68", - "test/unit/consensus/armed_map/fingerprint_v2.test.js": "8bbb1aab764e0740", - "test/unit/consensusPinBoot.test.js": "03d0b8b6f4107f85", - "test/unit/contractStateSubtree.test.js": "59a7a5d4db89272b", - "test/unit/cooldownCredits.test.js": "24a72d7a2b04edd3", - "test/unit/corsOrigin.test.js": "e3fcef2cb94f7253", - "test/unit/coverage-thresholds-sync.test.js": "4405034a199528ec", - "test/unit/db-schema-evolution.test.js": "f1a54aa20d85cdc2", - "test/unit/db-schema-selfheal-startup.test.js": "324f0246f861a9ae", - "test/unit/db.replicaStatus.test.js": "43cffa3fce90993d", - "test/unit/db.stakeWeightCollation.test.js": "73c6c3088149dafc", - "test/unit/db.stakeWeightsAsOf.test.js": "ee110e57ac665f06", - "test/unit/db.swqSourceCap.test.js": "910a4f5c866b3b8b", - "test/unit/db.test.js": "9814f122bb680067", - "test/unit/db.weightlessStakeRow.test.js": "8597f4afbe495528", - "test/unit/deactivation-block-mirror.test.js": "be9b26be638dfbe0", - "test/unit/decoderTableClassification.test.js": "f15a3c001afd798e", - "test/unit/derivedRewards.test.js": "a10aa497412e5a05", - "test/unit/escrowLeafSubtree.test.js": "de3963533a177029", - "test/unit/followerArmingBalances.test.js": "564769c03a6a6f31", - "test/unit/followerMissingPriorRoot.test.js": "e76d24fca4e63da9", - "test/unit/generatedColumns.test.js": "774b6ea9b6b7fe1e", - "test/unit/getBlockLeafRows.canonical.test.js": "7bd37c7fd3de6737", + "test/unit/consensus/armed_map/completeness.test.js": "316993ccc3fd07eb", + "test/unit/consensus/armed_map/falsification.test.js": "5bfa00fa6ab5f2b4", + "test/unit/consensus/armed_map/fingerprint.test.js": "5560ded00c05d876", + "test/unit/consensus/gate_registry.test.js": "0a0b1c0489a3d846", + "test/unit/consensus_pin_boot.test.js": "03d0b8b6f4107f85", + "test/unit/consensus_primitive_conformance.test.js": "091ee0965b4ff600", + "test/unit/contractStateSubtree.test.js": "8340f62c3bf4e723", + "test/unit/contractStateSubtree.test/contract_state_root_arming_boundary.test.js": "1e2917ef8e99fd7f", + "test/unit/contractStateSubtree.test/contract_state_root_frozen_row.test.js": "3498ab5bdacfbd7d", + "test/unit/contractStateSubtree.test/contract_state_root_incremental_equals.test.js": "ed046892e95da65f", + "test/unit/contractStateSubtree.test/contract_state_root_orphan_and_snapshot.test.js": "82ad4278d662f2a2", + "test/unit/contractStateSubtree.test/contract_state_root_shadow_derivation.test.js": "f904093dd63c32cc", + "test/unit/contractStateSubtree.test/contract_state_root_strict_read_faults.test.js": "151ff98884592964", + "test/unit/contractStateSubtree.test/contract_state_root_strict_reads.test.js": "6d955dc4007ee59e", + "test/unit/cooldown_credits.test.js": "24a72d7a2b04edd3", + "test/unit/cors_origin.test.js": "e3fcef2cb94f7253", + "test/unit/coverage_thresholds_sync.test.js": "4405034a199528ec", + "test/unit/db.test.js": "3e452242329a55a6", + "test/unit/db.test/01_database_do_query.test.js": "35f586531a7008e6", + "test/unit/db.test/02_database_commit_transaction.test.js": "202bed8f78d5d96d", + "test/unit/db.test/03_database_verify_sync_tables.test.js": "db839ea0e9db1207", + "test/unit/db.test/04_database_add_missing_columns_edge_branches.test.js": "2b8574874fbaf660", + "test/unit/db.test/05_database_get_emission_rows_for_block.test.js": "c8f08c761facce4a", + "test/unit/db.test/06_database_halt_methods.test.js": "d54620a13360f8b5", + "test/unit/db.test/07_database_replicate_schema.test.js": "98e33e68315706b4", + "test/unit/db.test/08_database_ensure_replica_secondary_indexes_votes_append_only_migration.test.js": "93be970735a5f782", + "test/unit/db.test/09_database_ensure_replica_secondary_indexes_validator_rewards_reward_unique_qualifier_key.test.js": "4149fd390fa625eb", + "test/unit/db_replica_status.test.js": "43cffa3fce90993d", + "test/unit/db_schema_evolution.test.js": "5a71a37ad253d732", + "test/unit/db_schema_evolution.test/01_database_add_missing_columns_auto_increment_key_clause.test.js": "75e74f104d7e1701", + "test/unit/db_schema_evolution.test/02_database_ensure_replicated_columns_nullability_relaxation.test.js": "f610ec2582be7e3b", + "test/unit/db_schema_selfheal_startup.test.js": "324f0246f861a9ae", + "test/unit/db_stake_weight_collation.test.js": "73c6c3088149dafc", + "test/unit/db_stake_weights_as_of.test.js": "6aba3ac215f51b2b", + "test/unit/db_swq_source_cap.test.js": "910a4f5c866b3b8b", + "test/unit/db_weightless_stake_row.test.js": "8597f4afbe495528", + "test/unit/deactivation_block_mirror.test.js": "be9b26be638dfbe0", + "test/unit/decoder_table_classification.test.js": "f15a3c001afd798e", + "test/unit/derived_rewards.test.js": "a10aa497412e5a05", + "test/unit/escrowLeafSubtree.test.js": "07fa9a8166b63715", + "test/unit/escrowLeafSubtree.test/xchain_esc_locked_leaf_shadow_thread.test.js": "6aff270db2df60a7", + "test/unit/escrowLeafSubtree.test/xchain_esc_locked_leaf_the.test.js": "6f3bf3f9c5f1d95a", + "test/unit/follower_arming_balances.test.js": "564769c03a6a6f31", + "test/unit/follower_missing_prior_root.test.js": "e76d24fca4e63da9", + "test/unit/generated_columns.test.js": "774b6ea9b6b7fe1e", + "test/unit/get_block_leaf_rows_canonical.test.js": "7bd37c7fd3de6737", + "test/unit/hash_verifier.test.js": "ef4deb6bc7390bd3", + "test/unit/health/carrier_logic.test.js": "c54a906a079d6748", "test/unit/health_halt_verdict.test.js": "b692b313f677d5c4", - "test/unit/hubConsensusHash.test.js": "37100c93c95b19e0", + "test/unit/hub_client.test.js": "68687be53be6c143", + "test/unit/hub_client.test/01_get_indexer_configs.test.js": "7594e07757fb9953", + "test/unit/hub_client.test/02_get_decoder_configs.test.js": "d87bf948f96ea270", + "test/unit/hub_client.test/03_constructor_array_form.test.js": "7d990c7da364fa60", + "test/unit/hub_client.test/04_call_multi_endpoint_fallback.test.js": "80af9bed82bea8f3", + "test/unit/hub_client.test/05_getallconfigs_cursor_watermark_handling.test.js": "b80dca04c74b600c", + "test/unit/hub_client.test/06_getallconfigs_watermark_regression.test.js": "982b7874b134e4c3", + "test/unit/hub_client.test/07_hub_config_regressed.test.js": "2696e26e03274736", + "test/unit/hub_client.test/08_parse_port.test.js": "b642edb3ab6a5231", + "test/unit/hub_client.test/09_parse_endpoints.test.js": "52fd8b56df0fa3ee", + "test/unit/hub_client.test/10_credential_tier.test.js": "a9b77afc5d938dab", + "test/unit/hub_consensus_hash.test.js": "37100c93c95b19e0", "test/unit/merkle.test.js": "780d1a01b4ffea14", - "test/unit/missingTables.test.js": "409fbf440d108d07", + "test/unit/merkle_tree.test.js": "0c488b6b47a588af", + "test/unit/missing_tables.test.js": "3b26854153f9cf95", "test/unit/observability.test.js": "ca8fa416b5e8a763", - "test/unit/pinnedValidators.test.js": "8908175de26042da", - "test/unit/poolSizing.test.js": "ae699f6978a9fbbd", - "test/unit/protocolAddressRoles.twin.test.js": "5d511d8452dc7256", - "test/unit/recoveryRewards.test.js": "c7ffd8486a3a6f7e", - "test/unit/replicaFreshness.test.js": "ebef09fb184feed7", - "test/unit/replicaGapStatus.test.js": "bcf51d25df891659", + "test/unit/pinned_validators.test.js": "8908175de26042da", + "test/unit/pool_sizing.test.js": "ae699f6978a9fbbd", + "test/unit/protocol_address_roles_twin.test.js": "5d511d8452dc7256", + "test/unit/recovery_rewards.test.js": "c7ffd8486a3a6f7e", + "test/unit/replica_freshness.test.js": "ebef09fb184feed7", + "test/unit/replica_gap_status.test.js": "bcf51d25df891659", "test/unit/replica_secondary_indexes.test.js": "685672ba7325e614", - "test/unit/replicatedDatetimeColumns.test.js": "007aec547cbd73a8", - "test/unit/replicatedTables.test.js": "af5a41ac8b61580f", - "test/unit/rollback-coverage.test.js": "808d4ec2c5ddf345", - "test/unit/schema-version-gate.test.js": "a0553a057c488031", - "test/unit/schema-version.test.js": "73d07ebbe093fcfd", - "test/unit/security/configuration/dependency-advisories.test.js": "5cc2b8143bdd5808", + "test/unit/replicated_datetime_columns.test.js": "007aec547cbd73a8", + "test/unit/replicated_tables.test.js": "af5a41ac8b61580f", + "test/unit/repo_guards/carrier_logic_pin.test.js": "675159dfa1a4a4c2", + "test/unit/rollback_coverage.test.js": "b34bca1164f2f052", + "test/unit/schema_version.test.js": "73d07ebbe093fcfd", + "test/unit/schema_version_gate.test.js": "a0553a057c488031", + "test/unit/security/configuration/dependency_advisories.test.js": "5cc2b8143bdd5808", + "test/unit/server_poller.test.js": "fc2e4e6f74912b6b", + "test/unit/server_poller.test/01_resume_cursor_restart_resume_regression.test.js": "48914b893fa0ef67", + "test/unit/server_poller.test/02_seed_reorg_guard_hash_durable_reorg_guard_seed_regression.test.js": "9e1eab683f917093", + "test/unit/server_poller.test/03_backfill_gaps_regression.test.js": "3107b91431c55ba5", + "test/unit/server_poller.test/04_build_block_payload.test.js": "62101a3cfb162f48", + "test/unit/server_poller.test/05_build_block_payload_2.test.js": "c4e8870b7986e321", + "test/unit/server_poller.test/06_update_status.test.js": "71dbe5f3ab51e1b0", + "test/unit/server_poller.test/07_stop.test.js": "14cea56fa69537cd", + "test/unit/server_poller.test/08_poll_snapshot_pinning_h_p2.test.js": "f9851634c56991cb", + "test/unit/server_poller_action_scoped_probe.test.js": "d7ac1268f904a175", "test/unit/shutdown.test.js": "e4081567250aec28", - "test/unit/sibling-coverage.test.js": "d8d1e52267ea606f", - "test/unit/sqlUtil.test.js": "40158d38b88066f8", - "test/unit/stakesValidatorSetParity.test.js": "e89c73ba3a32ab98", - "test/unit/state-hash-index-map.test.js": "34ecc125f5c3c276", - "test/unit/stateCommitment.batchedNodeWrites.test.js": "e77b37f7efbcac18", - "test/unit/stateCommitment.orphanStats.test.js": "7cdc0abf30a6f6ac", - "test/unit/stateCommitment.test.js": "e34cac5673dfa0d1", - "test/unit/stateCommitmentStrictReads.test.js": "16a6b835bcc569c7", - "test/unit/stateSubtreeActivation.test.js": "1b01123efc4dff07", - "test/unit/state_key_collation_activation.test.js": "503d2c2e161e195c", - "test/unit/streamScopeColumns.test.js": "841f60ebb29a8983", - "test/unit/surrogateIdRegistry.test.js": "73126c25800a9bdc", - "test/unit/syncTableClassification.test.js": "f4ec21668243211b", + "test/unit/sibling_coverage.test.js": "d8d1e52267ea606f", + "test/unit/snapshot_builder.test.js": "b3e2a0142aa3664a", + "test/unit/snapshot_builder.test/01_stream_full_snapshot.test.js": "72c2cac4e73d4e53", + "test/unit/snapshot_builder.test/02_stream_incremental_snapshot.test.js": "b7dd6bd9b2a33a4e", + "test/unit/snapshot_builder.test/03_stream_table_rows_by_id.test.js": "2f20c354797e7735", + "test/unit/snapshot_builder.test/04_stream_dispensers.test.js": "f2f7e767a0317d4c", + "test/unit/snapshot_builder.test/05_transactional_boundary.test.js": "6cd305fd75432e2c", + "test/unit/snapshot_builder.test/06_branch_coverage.test.js": "4c7a6b9fa31958b9", + "test/unit/snapshot_builder.test/07_paging_stream_client_abort.test.js": "a659b18e95ae431f", + "test/unit/snapshot_builder.test/08_snapshot_stream_writer_backpressure_client_abort.test.js": "90829ca9a8a00309", + "test/unit/snapshot_builder.test/09_stream_full_snapshot_client_abort.test.js": "8602ff4f2d85519c", + "test/unit/snapshot_builder.test/10_stream_incremental_snapshot_lookup_paging.test.js": "7b09ebaa3cd21c00", + "test/unit/snapshot_builder.test/11_stream_incremental_snapshot_snapshot_replication_tables.test.js": "3f757b2a543b0143", + "test/unit/snapshot_builder.test/12_snapshot_concurrency_cap.test.js": "81aeefdb52ea39d2", + "test/unit/sql_util.test.js": "40158d38b88066f8", + "test/unit/stakes_validator_set_parity.test.js": "e89c73ba3a32ab98", + "test/unit/stateSubtreeActivation.test.js": "a2343508ab4cdd95", + "test/unit/stateSubtreeActivation.test/state_root_reserved_sub_trees.test.js": "d0ebbb448921f133", + "test/unit/stateSubtreeActivation.test/state_root_reserved_sub_trees_2.test.js": "ee22ef37c7d06c2b", + "test/unit/stateSubtreeActivation.test/state_root_reserved_sub_trees_armed_set.test.js": "8e78b69ca3426aa3", + "test/unit/state_commitment.test.js": "e34cac5673dfa0d1", + "test/unit/state_commitment_batched_node_writes.test.js": "cf99cbc50f631839", + "test/unit/state_commitment_batched_node_writes.test/01_stakes_subtree_rebuilds_only_on_change.test.js": "c5c4b726fc0811ec", + "test/unit/state_commitment_batched_node_writes.test/02_db_node_store_put_many_sql_shape.test.js": "e8b11f7dc180370c", + "test/unit/state_commitment_orphan_stats.test.js": "7cdc0abf30a6f6ac", + "test/unit/state_commitment_strict_reads.test.js": "2d5af37f72b7535a", + "test/unit/state_hash.test.js": "c54bb56b0f6fae1f", + "test/unit/state_hash_index_map.test.js": "34ecc125f5c3c276", + "test/unit/stream_scope_columns.test.js": "841f60ebb29a8983", + "test/unit/surrogate_id_registry.test.js": "73126c25800a9bdc", "test/unit/sync_meta_client_retention.test.js": "1331c4cc0e5fd805", - "test/unit/tableContentParity.test.js": "57cf128bdceb5a34", + "test/unit/sync_service.test.js": "d43f78d5b62fbee6", + "test/unit/sync_service.test/01_discover_chains.test.js": "4938e9a593e806aa", + "test/unit/sync_service.test/02_start_server_mode.test.js": "7b5dc0d725692134", + "test/unit/sync_service.test/03_start_client_mode.test.js": "28b5b3553b3a0524", + "test/unit/sync_service.test/04_start_client_sync_for_chain.test.js": "d491968d8d9a3eed", + "test/unit/sync_service.test/05_start_poller_for_chain.test.js": "eadfdc0dec6a56cd", + "test/unit/sync_service.test/06_schedule_hub_repoll.test.js": "987a7188bf95b1e7", + "test/unit/sync_service.test/07_wait_for_hub_timeout.test.js": "16b6025bc75d7d05", + "test/unit/sync_service.test/08_get_hub_config_age_seconds.test.js": "1628e91f205184a5", + "test/unit/sync_service.test/09_get_client_sync_state.test.js": "d2fffeabd095588e", + "test/unit/sync_service.test/10_get_client_sync.test.js": "b92e0d472730652e", + "test/unit/sync_service.test/11_mode_branching_in_start.test.js": "131ce9ddc181014a", + "test/unit/sync_service.test/12_startup_readiness_is_ready.test.js": "0bdf5df327f12392", + "test/unit/sync_table_classification.test.js": "f4ec21668243211b", + "test/unit/table_content_parity.test.js": "3f4b732becaa031e", + "test/unit/table_content_parity.test/01_content_digest.test.js": "3787112c2730702b", + "test/unit/table_content_parity.test/02_compute_table_content_checksums.test.js": "347de06fd7b53919", + "test/unit/table_content_parity.test/03_compare_table_content.test.js": "39c89678ecd7b9af", + "test/unit/table_content_parity.test/04_wiring.test.js": "0193b2edcc8a3f28", "test/unit/train_activation.test.js": "4bbfbfece133da72", - "test/unit/train_activation_twin.test.js": "ddfedb4e7f598989", - "test/unit/updatedRows.test.js": "41839f13ef76cf66", - "test/unit/utf8mb4-replica-widen.test.js": "9e46fbfae5839c05", + "test/unit/train_activation_twin.test.js": "be30d095ec85b25c", + "test/unit/transparency_log.test.js": "09cd28d5ace1d077", + "test/unit/transparency_log_readonly.test.js": "438f210bee5c5290", + "test/unit/transparency_log_retention.test.js": "77025ae7ee6bc534", + "test/unit/updated_rows.test.js": "f97b150a709be189", + "test/unit/utf8mb4_replica_widen.test.js": "9e46fbfae5839c05", "test/unit/utility.test.js": "436350992c034c95", "test/unit/validation.test.js": "8abfcb4541ad0c52", - "test/unit/wireCodec.test.js": "e283c1eed8fe0836" + "test/unit/wire_codec.test.js": "e283c1eed8fe0836" + } + }, + "test:boundary": { + "fileCount": 1, + "titleCount": 7, + "files": { + "test/boundary/consensus_constants.test.js": "e35b1c5b852ca0a8" + } + }, + "test:chaos": { + "fileCount": 5, + "titleCount": 41, + "files": { + "test/chaos/network_partition.test.js": "5912fee72a209060", + "test/chaos/replica_db_resilience.test.js": "9922e46bb18b4e81", + "test/chaos/source_db_resilience.test.js": "8612e91a8417e932", + "test/chaos/source_tip_read_failclosed.test.js": "319ef1f0f909fe9d", + "test/chaos/sync_resilience.test.js": "6c7b6eb10f3ced0f" + } + }, + "test:e2e": { + "fileCount": 26, + "titleCount": 75, + "files": { + "test/e2e/api.test.js": "50469ad456b170f3", + "test/e2e/cross_source.test.js": "f40b8e55e94cbb45", + "test/e2e/decoder_lifecycle.test.js": "5995b691d15f533d", + "test/e2e/decoder_lifecycle.test/01_proxy_trust_rate_limit_wiring.test.js": "b80b57d0513b68fe", + "test/e2e/decoder_lifecycle.test/02_cold_bootstrap.test.js": "8c55921529d21bf6", + "test/e2e/decoder_lifecycle.test/03_incremental_snapshot.test.js": "0a9f32b553d98066", + "test/e2e/decoder_lifecycle.test/04_reorg_rollback.test.js": "0d29ac0800550c53", + "test/e2e/decoder_lifecycle.test/05_live_websocket_sync.test.js": "a702de1223cc909f", + "test/e2e/delta_sync.test.js": "e6e589ac9f9ae7f9", + "test/e2e/dispensers_reconcile.test.js": "634548f3f3a46e14", + "test/e2e/error_recovery.test.js": "eebf1ea70711d38c", + "test/e2e/lifecycle.test.js": "7e7da713c509ab55", + "test/e2e/multi_chain.test.js": "eb566567b1f2f3e3", + "test/e2e/parity_interleave.test.js": "fc42c2acf198daed", + "test/e2e/proxy_trust.test.js": "4ad4873eb9337e0e", + "test/e2e/reorg.test.js": "ece551d681b05cc7", + "test/e2e/resume_parity.test.js": "5bb658138a2834df", + "test/e2e/resume_parity.test/01_10_2_reorg_while_disconnected_june_2026_production_scenario.test.js": "f5a2f59de279c2b5", + "test/e2e/resume_parity.test/02_10_3_torn_bootstrap_state.test.js": "f9be87c45e7f293b", + "test/e2e/resume_parity.test/03_10_4_divergence_halt_enforcement.test.js": "48fecddfd5831993", + "test/e2e/resume_parity.test/04_10_5_schema_drift_while_disconnected_self_heal.test.js": "b03d7c4fb1f16f36", + "test/e2e/resume_parity.test/05_10_6_connection_flapping.test.js": "51383bd614fcbfae", + "test/e2e/state_commitment_conformance.test.js": "a588bab2c93363ed", + "test/e2e/state_hash_fault_injection.test.js": "89f9f90cb8d11db4", + "test/e2e/transparency.test.js": "85c74ea535a25390", + "test/e2e/volume.test.js": "313ce50c8014b176" + } + }, + "test:e2e:ci": { + "fileCount": 26, + "titleCount": 75, + "files": { + "test/e2e/api.test.js": "50469ad456b170f3", + "test/e2e/cross_source.test.js": "f40b8e55e94cbb45", + "test/e2e/decoder_lifecycle.test.js": "5995b691d15f533d", + "test/e2e/decoder_lifecycle.test/01_proxy_trust_rate_limit_wiring.test.js": "b80b57d0513b68fe", + "test/e2e/decoder_lifecycle.test/02_cold_bootstrap.test.js": "8c55921529d21bf6", + "test/e2e/decoder_lifecycle.test/03_incremental_snapshot.test.js": "0a9f32b553d98066", + "test/e2e/decoder_lifecycle.test/04_reorg_rollback.test.js": "0d29ac0800550c53", + "test/e2e/decoder_lifecycle.test/05_live_websocket_sync.test.js": "a702de1223cc909f", + "test/e2e/delta_sync.test.js": "e6e589ac9f9ae7f9", + "test/e2e/dispensers_reconcile.test.js": "634548f3f3a46e14", + "test/e2e/error_recovery.test.js": "eebf1ea70711d38c", + "test/e2e/lifecycle.test.js": "7e7da713c509ab55", + "test/e2e/multi_chain.test.js": "eb566567b1f2f3e3", + "test/e2e/parity_interleave.test.js": "fc42c2acf198daed", + "test/e2e/proxy_trust.test.js": "4ad4873eb9337e0e", + "test/e2e/reorg.test.js": "ece551d681b05cc7", + "test/e2e/resume_parity.test.js": "5bb658138a2834df", + "test/e2e/resume_parity.test/01_10_2_reorg_while_disconnected_june_2026_production_scenario.test.js": "f5a2f59de279c2b5", + "test/e2e/resume_parity.test/02_10_3_torn_bootstrap_state.test.js": "f9be87c45e7f293b", + "test/e2e/resume_parity.test/03_10_4_divergence_halt_enforcement.test.js": "48fecddfd5831993", + "test/e2e/resume_parity.test/04_10_5_schema_drift_while_disconnected_self_heal.test.js": "b03d7c4fb1f16f36", + "test/e2e/resume_parity.test/05_10_6_connection_flapping.test.js": "51383bd614fcbfae", + "test/e2e/state_commitment_conformance.test.js": "a588bab2c93363ed", + "test/e2e/state_hash_fault_injection.test.js": "89f9f90cb8d11db4", + "test/e2e/transparency.test.js": "85c74ea535a25390", + "test/e2e/volume.test.js": "313ce50c8014b176" + } + }, + "test:fuzz": { + "fileCount": 6, + "titleCount": 55, + "files": { + "test/fuzz/suites/tier1_client_applier.fuzz.js": "1410e3f1c5abfb95", + "test/fuzz/suites/tier1_hash_verifier.fuzz.js": "517ad59201348d3a", + "test/fuzz/suites/tier2_client_rollback.fuzz.js": "fb2faaff7e9ed70f", + "test/fuzz/suites/tier2_hub_client.fuzz.js": "0a214ec4ff4e8d5c", + "test/fuzz/suites/tier2_server_poller.fuzz.js": "00ce7fb476e3182e", + "test/fuzz/suites/tier3_config.fuzz.js": "7435d3e8a1e6d309" + } + }, + "test:fuzz:quick": { + "fileCount": 6, + "titleCount": 55, + "files": { + "test/fuzz/suites/tier1_client_applier.fuzz.js": "1410e3f1c5abfb95", + "test/fuzz/suites/tier1_hash_verifier.fuzz.js": "517ad59201348d3a", + "test/fuzz/suites/tier2_client_rollback.fuzz.js": "fb2faaff7e9ed70f", + "test/fuzz/suites/tier2_hub_client.fuzz.js": "0a214ec4ff4e8d5c", + "test/fuzz/suites/tier2_server_poller.fuzz.js": "00ce7fb476e3182e", + "test/fuzz/suites/tier3_config.fuzz.js": "7435d3e8a1e6d309" + } + }, + "test:fuzz:tier1": { + "fileCount": 2, + "titleCount": 25, + "files": { + "test/fuzz/suites/tier1_client_applier.fuzz.js": "1410e3f1c5abfb95", + "test/fuzz/suites/tier1_hash_verifier.fuzz.js": "517ad59201348d3a" + } + }, + "test:fuzz:tier2": { + "fileCount": 3, + "titleCount": 23, + "files": { + "test/fuzz/suites/tier2_client_rollback.fuzz.js": "fb2faaff7e9ed70f", + "test/fuzz/suites/tier2_hub_client.fuzz.js": "0a214ec4ff4e8d5c", + "test/fuzz/suites/tier2_server_poller.fuzz.js": "00ce7fb476e3182e" + } + }, + "test:fuzz:tier3": { + "fileCount": 1, + "titleCount": 7, + "files": { + "test/fuzz/suites/tier3_config.fuzz.js": "7435d3e8a1e6d309" + } + }, + "test:integration": { + "fileCount": 28, + "titleCount": 109, + "files": { + "test/integration/armed_source_handshake.test.js": "b0d1b3c568451adf", + "test/integration/balance_rebuild_scoped.test.js": "d22ec38d3512da31", + "test/integration/binary_replication.test.js": "b270a2265a5c716a", + "test/integration/client_bootstrap.test.js": "a1c61939d5e79b8d", + "test/integration/client_live_sync.test.js": "ec77114beed6a450", + "test/integration/client_rollback.test.js": "01a0e95347ac133b", + "test/integration/emissions_parity.test.js": "37bc72a0a6979a91", + "test/integration/get_block_scoped_rows_lifecycle.test.js": "8ea1c406c845cec1", + "test/integration/index_map_parity.test.js": "d81e2076ef5e60ee", + "test/integration/index_map_parity_http.test.js": "c99ff09c7317dddf", + "test/integration/lifecycle.test.js": "be9bdba4e50a9357", + "test/integration/replication_insert_shape.test.js": "82de2fae4693c94d", + "test/integration/server_polling.test.js": "e9198b686f505dd5", + "test/integration/server_rest_api.test.js": "4d60233a4d0d52f7", + "test/integration/server_rest_api.test/01_get_status_db_type_chain_network.test.js": "c99af0a2bafdfce4", + "test/integration/server_rest_api.test/02_get_schema_db_type_chain_network.test.js": "f1150c948244069d", + "test/integration/server_rest_api.test/03_get_snapshot_db_type_chain_network.test.js": "7e0925801ccae7f1", + "test/integration/server_rest_api.test/04_get_snapshot_db_type_chain_network_since_block_height.test.js": "8f25bc9eed65018d", + "test/integration/server_rest_api.test/05_get_transparency_db_type_chain_network_roots.test.js": "52c69be5fa7605f0", + "test/integration/server_rest_api.test/06_get_transparency_db_type_chain_network_proof_block_index.test.js": "5b17637c84d5cb70", + "test/integration/server_rest_api.test/07_get_transparency_db_type_chain_network_root_latest.test.js": "3c190d07814f2bdb", + "test/integration/server_rest_api.test/08_proxy_trust_rate_limit_wiring.test.js": "68f10a273308ebbe", + "test/integration/server_websocket.test.js": "2c414fbb86440ec6", + "test/integration/snapshot_concurrency.test.js": "cad1d26d53c24f5a", + "test/integration/subtree_armed_follower.test.js": "f4f95d87d6f86904", + "test/integration/subtree_shadow_cross_twin.test.js": "20ed0b54513008c0", + "test/integration/token_supply_recompute.test.js": "5229b20ad602f73b", + "test/integration/transparency_log.test.js": "971aa02f9a73a797" + } + }, + "test:integration:ci": { + "fileCount": 24, + "titleCount": 99, + "files": { + "test/integration/armed_source_handshake.test.js": "b0d1b3c568451adf", + "test/integration/balance_rebuild_scoped.test.js": "d22ec38d3512da31", + "test/integration/binary_replication.test.js": "b270a2265a5c716a", + "test/integration/client_rollback.test.js": "01a0e95347ac133b", + "test/integration/get_block_scoped_rows_lifecycle.test.js": "8ea1c406c845cec1", + "test/integration/index_map_parity.test.js": "d81e2076ef5e60ee", + "test/integration/index_map_parity_http.test.js": "c99ff09c7317dddf", + "test/integration/replication_insert_shape.test.js": "82de2fae4693c94d", + "test/integration/server_polling.test.js": "e9198b686f505dd5", + "test/integration/server_rest_api.test.js": "4d60233a4d0d52f7", + "test/integration/server_rest_api.test/01_get_status_db_type_chain_network.test.js": "c99af0a2bafdfce4", + "test/integration/server_rest_api.test/02_get_schema_db_type_chain_network.test.js": "f1150c948244069d", + "test/integration/server_rest_api.test/03_get_snapshot_db_type_chain_network.test.js": "7e0925801ccae7f1", + "test/integration/server_rest_api.test/04_get_snapshot_db_type_chain_network_since_block_height.test.js": "8f25bc9eed65018d", + "test/integration/server_rest_api.test/05_get_transparency_db_type_chain_network_roots.test.js": "52c69be5fa7605f0", + "test/integration/server_rest_api.test/06_get_transparency_db_type_chain_network_proof_block_index.test.js": "5b17637c84d5cb70", + "test/integration/server_rest_api.test/07_get_transparency_db_type_chain_network_root_latest.test.js": "3c190d07814f2bdb", + "test/integration/server_rest_api.test/08_proxy_trust_rate_limit_wiring.test.js": "68f10a273308ebbe", + "test/integration/server_websocket.test.js": "2c414fbb86440ec6", + "test/integration/snapshot_concurrency.test.js": "cad1d26d53c24f5a", + "test/integration/subtree_armed_follower.test.js": "f4f95d87d6f86904", + "test/integration/subtree_shadow_cross_twin.test.js": "20ed0b54513008c0", + "test/integration/token_supply_recompute.test.js": "5229b20ad602f73b", + "test/integration/transparency_log.test.js": "971aa02f9a73a797" + } + }, + "test:integration:parity": { + "fileCount": 2, + "titleCount": 8, + "files": { + "test/integration/index_map_parity.test.js": "d81e2076ef5e60ee", + "test/integration/index_map_parity_http.test.js": "c99ff09c7317dddf" + } + }, + "test:mutate": { + "skipped": "not a mocha command (runs npx)" + }, + "test:mutate:check": { + "skipped": "not a mocha command (runs npx)" + }, + "test:mutate:quick": { + "skipped": "not a mocha command (runs npx)" + }, + "test:perf": { + "fileCount": 8, + "titleCount": 38, + "files": { + "test/perf/scenarios/01_payload_throughput.test.js": "3005f26e0e504c49", + "test/perf/scenarios/02_snapshot_performance.test.js": "e2e378802d6bcdbf", + "test/perf/scenarios/03_bootstrap_apply.test.js": "65bb959e23b70c91", + "test/perf/scenarios/04_subscriber_scaling.test.js": "87ba7838842f7cf2", + "test/perf/scenarios/05_sustained_sync.test.js": "bd1e405ed8d1de94", + "test/perf/scenarios/06_incremental_catchup.test.js": "1f961d589efa3f2e", + "test/perf/scenarios/07_rollback_performance.test.js": "9b652f1a15749f6a", + "test/perf/scenarios/08_bootstrap_stampede.test.js": "908f56d4f3992093" + } + }, + "test:perf:pool": { + "skipped": "not a mocha command (runs node)" + }, + "test:perf:quick": { + "fileCount": 8, + "titleCount": 38, + "files": { + "test/perf/scenarios/01_payload_throughput.test.js": "3005f26e0e504c49", + "test/perf/scenarios/02_snapshot_performance.test.js": "e2e378802d6bcdbf", + "test/perf/scenarios/03_bootstrap_apply.test.js": "65bb959e23b70c91", + "test/perf/scenarios/04_subscriber_scaling.test.js": "87ba7838842f7cf2", + "test/perf/scenarios/05_sustained_sync.test.js": "bd1e405ed8d1de94", + "test/perf/scenarios/06_incremental_catchup.test.js": "1f961d589efa3f2e", + "test/perf/scenarios/07_rollback_performance.test.js": "9b652f1a15749f6a", + "test/perf/scenarios/08_bootstrap_stampede.test.js": "908f56d4f3992093" + } + }, + "test:perf:stampede": { + "fileCount": 1, + "titleCount": 4, + "files": { + "test/perf/scenarios/08_bootstrap_stampede.test.js": "908f56d4f3992093" + } + }, + "test:regression": { + "fileCount": 70, + "titleCount": 585, + "files": { + "test/unit/balance_helpers.test.js": "b146f330faa567f9", + "test/unit/block_hasher.test.js": "b6f88326a1ba0d27", + "test/unit/blockhash_conformance_twin.test.js": "6f8cd171d7d29aa7", + "test/unit/checkpoint_quorum_flag_day.test.js": "7a4688817472b50c", + "test/unit/checkpoint_twin.test.js": "aed79f98d38bbde3", + "test/unit/client_applier.test/01_apply_full_snapshot.test.js": "1050d45e360d00f4", + "test/unit/client_sync.test/06_handle_event.test.js": "e962afbc1dd6ade5", + "test/unit/client_sync_checkpoint_quorum.test.js": "b57e7bf0add0a957", + "test/unit/client_sync_checkpoint_quorum.test/01_checkpoint_quorum_rotation_following.test.js": "5fd53912b63d1fe2", + "test/unit/client_sync_halt.test.js": "890c1afd26223048", + "test/unit/client_sync_halt.test/01_independent_recompute_halt.test.js": "86523982ea831a05", + "test/unit/client_sync_halt.test/02_bulk_range_boundary_recompute.test.js": "2de09f9ac8510fc7", + "test/unit/client_sync_halt.test/03_state_hash_apply_time_integrity_halt.test.js": "c887799f86d69a43", + "test/unit/client_sync_halt.test/04_verify_recompute_false_is_declared_unsafe.test.js": "eee91ecc715fb032", + "test/unit/client_sync_io.test/05_oversized_catch_up_fallback_routes_by_truncation.test.js": "5d1de29605d15857", + "test/unit/client_sync_io.test/06_decoder_completeness_check_on_a_truncated_replica.test.js": "5cb20fdb5738741b", + "test/unit/client_sync_io.test/07_indexer_head_fork_re_delivery.test.js": "0c06733c3bf59e5e", + "test/unit/client_sync_io.test/20_lookup_hole_repair_and_count_check_scoping_regression.test.js": "20341c70321425c4", + "test/unit/client_sync_source_quorum.test.js": "4d1ce9c4b6023937", + "test/unit/client_sync_tip_hash_refresh.test.js": "283afce58127f133", + "test/unit/client_sync_train_activation.test.js": "83fe31113184d5b3", + "test/unit/coins_conformance.test.js": "2442df610ebb6911", + "test/unit/consensus_primitive_conformance.test.js": "091ee0965b4ff600", + "test/unit/contractStateSubtree.test.js": "8340f62c3bf4e723", + "test/unit/contractStateSubtree.test/contract_state_root_arming_boundary.test.js": "1e2917ef8e99fd7f", + "test/unit/contractStateSubtree.test/contract_state_root_frozen_row.test.js": "3498ab5bdacfbd7d", + "test/unit/contractStateSubtree.test/contract_state_root_incremental_equals.test.js": "ed046892e95da65f", + "test/unit/contractStateSubtree.test/contract_state_root_orphan_and_snapshot.test.js": "82ad4278d662f2a2", + "test/unit/contractStateSubtree.test/contract_state_root_shadow_derivation.test.js": "f904093dd63c32cc", + "test/unit/contractStateSubtree.test/contract_state_root_strict_read_faults.test.js": "151ff98884592964", + "test/unit/contractStateSubtree.test/contract_state_root_strict_reads.test.js": "6d955dc4007ee59e", + "test/unit/db_replica_status.test.js": "43cffa3fce90993d", + "test/unit/db_swq_source_cap.test.js": "910a4f5c866b3b8b", + "test/unit/decoder_table_classification.test.js": "f15a3c001afd798e", + "test/unit/escrowLeafSubtree.test.js": "07fa9a8166b63715", + "test/unit/escrowLeafSubtree.test/xchain_esc_locked_leaf_shadow_thread.test.js": "6aff270db2df60a7", + "test/unit/escrowLeafSubtree.test/xchain_esc_locked_leaf_the.test.js": "6f3bf3f9c5f1d95a", + "test/unit/follower_arming_balances.test.js": "564769c03a6a6f31", + "test/unit/follower_missing_prior_root.test.js": "e76d24fca4e63da9", + "test/unit/generated_columns.test.js": "774b6ea9b6b7fe1e", + "test/unit/merkle.test.js": "780d1a01b4ffea14", + "test/unit/merkle_tree.test.js": "0c488b6b47a588af", + "test/unit/pinned_validators.test.js": "8908175de26042da", + "test/unit/protocol_address_roles_twin.test.js": "5d511d8452dc7256", + "test/unit/replicated_datetime_columns.test.js": "007aec547cbd73a8", + "test/unit/rollback_coverage.test.js": "4504591b9086da2b", + "test/unit/schema_version.test.js": "73d07ebbe093fcfd", + "test/unit/schema_version_gate.test.js": "a0553a057c488031", + "test/unit/security/configuration/dependency_advisories.test.js": "5cc2b8143bdd5808", + "test/unit/server_poller.test/01_resume_cursor_restart_resume_regression.test.js": "48914b893fa0ef67", + "test/unit/server_poller.test/02_seed_reorg_guard_hash_durable_reorg_guard_seed_regression.test.js": "9e1eab683f917093", + "test/unit/server_poller.test/03_backfill_gaps_regression.test.js": "3107b91431c55ba5", + "test/unit/server_poller.test/04_build_block_payload.test.js": "d6e6a07ac37b541c", + "test/unit/server_poller.test/05_build_block_payload_2.test.js": "9cca6fcd72577c24", + "test/unit/snapshot_builder.test/04_stream_dispensers.test.js": "654c349590fc25ab", + "test/unit/snapshot_builder.test/06_branch_coverage.test.js": "b4f0d893b0d9c977", + "test/unit/stakes_validator_set_parity.test.js": "e89c73ba3a32ab98", + "test/unit/stateSubtreeActivation.test.js": "a2343508ab4cdd95", + "test/unit/stateSubtreeActivation.test/state_root_reserved_sub_trees.test.js": "d0ebbb448921f133", + "test/unit/stateSubtreeActivation.test/state_root_reserved_sub_trees_2.test.js": "ee22ef37c7d06c2b", + "test/unit/stateSubtreeActivation.test/state_root_reserved_sub_trees_armed_set.test.js": "8e78b69ca3426aa3", + "test/unit/state_commitment.test.js": "e34cac5673dfa0d1", + "test/unit/state_commitment_batched_node_writes.test.js": "cf99cbc50f631839", + "test/unit/state_commitment_batched_node_writes.test/01_stakes_subtree_rebuilds_only_on_change.test.js": "c5c4b726fc0811ec", + "test/unit/state_commitment_batched_node_writes.test/02_db_node_store_put_many_sql_shape.test.js": "e8b11f7dc180370c", + "test/unit/state_commitment_orphan_stats.test.js": "7cdc0abf30a6f6ac", + "test/unit/state_hash.test.js": "c54bb56b0f6fae1f", + "test/unit/state_hash_index_map.test.js": "34ecc125f5c3c276", + "test/unit/stream_scope_columns.test.js": "841f60ebb29a8983", + "test/unit/surrogate_id_registry.test.js": "73126c25800a9bdc" + } + }, + "test:security": { + "fileCount": 14, + "titleCount": 157, + "files": { + "test/security/api_rate_limit_proxy_security.test.js": "b12d9fe0288ee479", + "test/security/api_security.test.js": "05a50fe7a5a97bc8", + "test/security/block_broadcaster_security.test.js": "cc72fad7b0a4aab2", + "test/security/client_applier_security.test.js": "207558fd52fb2bf8", + "test/security/client_sync_security.test.js": "4f4e462e9354e761", + "test/security/client_sync_security.test/01_handle_reorg_max_rollback_depth.test.js": "068103cacb04749f", + "test/security/client_sync_security.test/02_handle_block_strict_cross_source_timeout.test.js": "50994261d736f8b5", + "test/security/client_sync_security.test/03_connect_web_socket_max_payload.test.js": "22f878636d1e21f6", + "test/security/client_sync_security.test/04_web_socket_message_handler_event_validation.test.js": "598cee8913d7c5bc", + "test/security/validation.test.js": "c7cbd5dc4224f664", + "test/security/validation.test/01_validate_ddl.test.js": "c7d55f705a9a8f0d", + "test/security/validation.test/02_validate_ws_event.test.js": "09f74f1da00d6cad", + "test/security/validation.test/03_extract_column_names.test.js": "f45334c14832a872", + "test/security/validation.test/04_extract_column_definition.test.js": "2dcdcb24f7d411bb" + } + }, + "test:smoke": { + "fileCount": 2, + "titleCount": 17, + "files": { + "test/smoke/client_smoke.test.js": "350a60ae36012e8e", + "test/smoke/server_smoke.test.js": "d1d68be89e493fba" } } } diff --git a/bin/pins/carrier-logic.json b/bin/pins/carrier-logic.json index 74046447..2faff414 100644 --- a/bin/pins/carrier-logic.json +++ b/bin/pins/carrier-logic.json @@ -2,83 +2,68 @@ "version": 1, "entries": { "archive_rollback_author_scope_activation": { - "path": "src/archive_rollback_author_scope_activation.js", + "path": "src/consensus/gates/archive_rollback_author_scope_gate.js", "hash": "9f65819d7885209579a3deee1aaf7bc6363895779d0d599c76191d51e5762d46", "twins": [ "xchain-indexer" ] }, - "checkpoint_commitment_activation": { - "path": "src/checkpoint_commitment_activation.js", - "hash": "bd9b1032d5e1efd65e4af97d80119d178b5c5cb33eb4ea9fc3a4963e6577de30", - "twins": [ - "xchain-hub", - "xchain-indexer" - ] - }, "consensus-constants": { "path": "src/consensus-constants.js", "hash": "1ac5e4445d59152e92a2d9d0d2253ff34b7663f6be0f76fe5028ce3780081e14", "twins": [] }, "equivocation_header": { - "path": "src/equivocation_header.js", + "path": "src/consensus/equivocation_header.js", "hash": "74a151e91bb72581fce3efe097452afa10603417d20eb008e58d1833f4a889f0", "twins": [ "xchain-indexer" ] }, "stake_weight_collation_activation": { - "path": "src/stake_weight_collation_activation.js", + "path": "src/consensus/gates/stake_weight_collation_gate.js", "hash": "d651ee809b2004e10497bafbe56446dae2f78d5b94e0826b5a063be4a5cf42d4", "twins": [ "xchain-indexer" ] }, "stake_weighted_quorum": { - "path": "src/stake_weighted_quorum.js", + "path": "src/consensus/stake_weighted_quorum.js", "hash": "afaee5777e8d909eace7a7106b294797014f74929fc4302c50a2ec31ac77a847", "twins": [ "xchain-indexer" ] }, "stateHash": { - "path": "src/stateHash.js", + "path": "src/consensus/state_hash.js", "hash": "b410a31b2888a718982824da33e1fac4ec09cf65bea7e1b50e8b22dc50259c0b", "twins": [ "xchain-indexer" ] }, "state_commitment_activation": { - "path": "src/state_commitment_activation.js", + "path": "src/consensus/gates/state_commitment_gate.js", "hash": "a0d934c568751b0c5427c5a1934193b77e696092a97f96160ac77a04bdf575cf", "twins": [ "xchain-indexer" ] }, - "state_key_collation_activation": { - "path": "src/state_key_collation_activation.js", - "hash": "555630bc80f7f8fb563198859cc5ff328a3d0847f038ce1c88806123264f6bbd", - "twins": [ - "xchain-indexer" - ] - }, "state_subtree_activation": { - "path": "src/state_subtree_activation.js", + "path": "src/consensus/gates/state_subtree_gate.js", "hash": "3a3afec8a2591ababf19f289c9879aa5b0ea299eed8b7aa8723b774e0386c1d1", "twins": [ "xchain-indexer" ] }, "swq_source_cap_activation": { - "path": "src/swq_source_cap_activation.js", + "path": "src/consensus/gates/swq_source_cap_gate.js", "hash": "07148486fb1f8869168eadcc08701cab41a275c90eff873df28b2feac2cfa0ef", "twins": [ "xchain-indexer" ] }, "train_activation": { - "path": "src/train_activation.js", + "path": "src/consensus/gates/train_gate.js", "hash": "0e52179db25e4ef767aa8f695604b37a4a8d7c2dcc70afafadbd40b5760ca9eb", "twins": [ "xchain-indexer" @@ -253,6 +238,119 @@ "to": "0e52179db25e4ef767aa8f695604b37a4a8d7c2dcc70afafadbd40b5760ca9eb", "reason": "registry conversion (rows 12, 13, 14)", "date": "2026-09-16" + }, + { + "id": "checkpoint_commitment_activation", + "from": "bd9b1032d5e1efd65e4af97d80119d178b5c5cb33eb4ea9fc3a4963e6577de30", + "to": null, + "reason": "W5 consolidation (row 21)", + "date": "2026-09-16" + }, + { + "id": "state_key_collation_activation", + "from": "555630bc80f7f8fb563198859cc5ff328a3d0847f038ce1c88806123264f6bbd", + "to": null, + "reason": "W5 consolidation (row 21)", + "date": "2026-09-16" + }, + { + "id": "archive_rollback_author_scope_activation", + "from": "9f65819d7885209579a3deee1aaf7bc6363895779d0d599c76191d51e5762d46", + "to": "9f65819d7885209579a3deee1aaf7bc6363895779d0d599c76191d51e5762d46", + "path": { + "from": "src/archive_rollback_author_scope_activation.js", + "to": "src/consensus/gates/archive_rollback_author_scope_gate.js" + }, + "date": "2026-09-16", + "reason": "W5 consolidation (row 21)" + }, + { + "id": "stake_weight_collation_activation", + "from": "d651ee809b2004e10497bafbe56446dae2f78d5b94e0826b5a063be4a5cf42d4", + "to": "d651ee809b2004e10497bafbe56446dae2f78d5b94e0826b5a063be4a5cf42d4", + "path": { + "from": "src/stake_weight_collation_activation.js", + "to": "src/consensus/gates/stake_weight_collation_gate.js" + }, + "date": "2026-09-16", + "reason": "W5 consolidation (row 21)" + }, + { + "id": "state_commitment_activation", + "from": "a0d934c568751b0c5427c5a1934193b77e696092a97f96160ac77a04bdf575cf", + "to": "a0d934c568751b0c5427c5a1934193b77e696092a97f96160ac77a04bdf575cf", + "path": { + "from": "src/state_commitment_activation.js", + "to": "src/consensus/gates/state_commitment_gate.js" + }, + "date": "2026-09-16", + "reason": "W5 consolidation (row 21)" + }, + { + "id": "state_subtree_activation", + "from": "3a3afec8a2591ababf19f289c9879aa5b0ea299eed8b7aa8723b774e0386c1d1", + "to": "3a3afec8a2591ababf19f289c9879aa5b0ea299eed8b7aa8723b774e0386c1d1", + "path": { + "from": "src/state_subtree_activation.js", + "to": "src/consensus/gates/state_subtree_gate.js" + }, + "date": "2026-09-16", + "reason": "W5 consolidation (row 21)" + }, + { + "id": "swq_source_cap_activation", + "from": "07148486fb1f8869168eadcc08701cab41a275c90eff873df28b2feac2cfa0ef", + "to": "07148486fb1f8869168eadcc08701cab41a275c90eff873df28b2feac2cfa0ef", + "path": { + "from": "src/swq_source_cap_activation.js", + "to": "src/consensus/gates/swq_source_cap_gate.js" + }, + "date": "2026-09-16", + "reason": "W5 consolidation (row 21)" + }, + { + "id": "train_activation", + "from": "0e52179db25e4ef767aa8f695604b37a4a8d7c2dcc70afafadbd40b5760ca9eb", + "to": "0e52179db25e4ef767aa8f695604b37a4a8d7c2dcc70afafadbd40b5760ca9eb", + "path": { + "from": "src/train_activation.js", + "to": "src/consensus/gates/train_gate.js" + }, + "date": "2026-09-16", + "reason": "W5 consolidation (row 21)" + }, + { + "id": "stateHash", + "from": "b410a31b2888a718982824da33e1fac4ec09cf65bea7e1b50e8b22dc50259c0b", + "to": "b410a31b2888a718982824da33e1fac4ec09cf65bea7e1b50e8b22dc50259c0b", + "path": { + "from": "src/stateHash.js", + "to": "src/consensus/state_hash.js" + }, + "date": "2026-09-16", + "reason": "W5 consolidation (row 21)" + }, + { + "id": "equivocation_header", + "from": "74a151e91bb72581fce3efe097452afa10603417d20eb008e58d1833f4a889f0", + "to": "74a151e91bb72581fce3efe097452afa10603417d20eb008e58d1833f4a889f0", + "path": { + "from": "src/equivocation_header.js", + "to": "src/consensus/equivocation_header.js" + }, + "date": "2026-09-16", + "reason": "W5 consolidation (row 21)" + }, + { + "id": "stake_weighted_quorum", + "from": "afaee5777e8d909eace7a7106b294797014f74929fc4302c50a2ec31ac77a847", + "to": "afaee5777e8d909eace7a7106b294797014f74929fc4302c50a2ec31ac77a847", + "path": { + "from": "src/stake_weighted_quorum.js", + "to": "src/consensus/stake_weighted_quorum.js" + }, + "date": "2026-09-16", + "reason": "W5 consolidation (row 21)" } ] } diff --git a/bin/pins/identity.json b/bin/pins/identity.json index 730f40bb..0cd4d957 100644 --- a/bin/pins/identity.json +++ b/bin/pins/identity.json @@ -1,6 +1,5 @@ { - "armed_map_fingerprint": "69934f9b966c1c491fb0e737a41730488c729e3c209f1eda44b3ec7f6d2d6193", - "armed_map_fingerprint_v2": "69934f9b966c1c491fb0e737a41730488c729e3c209f1eda44b3ec7f6d2d6193", + "armed_map_fingerprint": "f3d4455007a84ab8000c47f586c0806097449574002f4bcf0f043ef3998a87d1", "armed_map_fingerprint_version": 2, "armedMapRows": { "archive_rollback_author_scope_activation.ARCHIVE_AUTHOR_SCOPE_JOIN_SQL": "c8b6c1753f86fb65689fbc5d72f001e9467d5553a91895a21c9cf48d643e8895", @@ -41,10 +40,10 @@ "swq_source_cap_activation.STAKE_WEIGHT_MAX_KEYS_PER_SOURCE": "a68b412c4282555f15546cf6e1fc42893b7e07f271557ceb021821098dd66c1b", "swq_source_cap_activation.STAKE_WEIGHT_MAX_SOURCES": "40510175845988f13f6162ed8526f0b09f73384467fa855e1e79b44a56562a58", "swq_source_cap_activation.SWQ_SOURCE_CAP_ACTIVATION": "d9105d53199963f94287f25b3d87d1e625b77d56ac8baab6d6ee64029b0fae74", - "train_activation.TRAIN_ACTIVATION": "8f740a4fe0949e295750bdf03de698c1914c5d584f617c179ca93910ab43d26e" + "train_activation.TRAIN_ACTIVATION": "3f842b0a9bec3dfc429b72e9172b941e262d8a1eef56eb2b4c60f63fdd90b8e4" }, "armed_map_rows": 39, - "carrier_logic_digest": "cad8451409684926fbd52dfad60324c9e933adb794e468eb3e93f16704e75953", + "carrier_logic_digest": "f142db83339b2a74577e6e79d49cffc45c45ac642bcd57609b554f98a2f2e068", "vendoredCoins": { "src/coins/BTC.js": "900d82359d27269ebb775a207e84cac7ac0702f57f07c0239d5406f2a0ec6c90", "src/coins/DOGE.js": "a0952d619edec50c09d0cbac90023cba2e8e75f0fa98b650e2ee1f4eadd7540b", diff --git a/bin/restore_comments.js b/bin/restore_comments.js index 68645401..a77d2631 100644 --- a/bin/restore_comments.js +++ b/bin/restore_comments.js @@ -59,15 +59,19 @@ const { execFileSync } = require('child_process'); const REPO_ROOT = path.resolve(__dirname, '..'); -// Files this repo carries but does not author. A consensus carrier is hashed by -// name and bytes, so a restored comment moves the armed-map fingerprint; a twin -// is compared with its canonical copy; a vendored file is refreshed by a script. -// Their deleted lines are the canonical repo's to put back, never this one's. +// Files this repo carries but does not author. A twin is compared byte for byte +// with its canonical copy (the indexer's, through the platform's reconcile +// check) and a vendored file is refreshed by a script, so a comment restored +// here alone reads as drift at the next check. Their deleted lines are the +// canonical repo's to put back, never this one's. The activation gates and the +// three carriers sit under src/consensus/ since the activation-registry W5 +// window (the same tail as the indexer's copies); the armed-map fingerprint no +// longer hashes any file by name, so nothing here is frozen for its own sake. const FROZEN = [ /^src\/coins\//, /^src\/observability\//, - /^src\/[a-z_]+_activation\.js$/, - /^src\/(stateHash|equivocation_header|stake_weighted_quorum|consensus-constants)\.js$/, - /^src\/(merkle|contract_state_subtree|escrow_leaf_subtree|table_lifecycle|stateCommitment|checkpoint|armedMapFingerprint)\.js$/, + /^src\/consensus\/gates\/[a-z_]+_gate\.js$/, + /^src\/consensus\/(state_hash|equivocation_header|stake_weighted_quorum)\.js$/, + /^src\/(merkle|contract_state_subtree|escrow_leaf_subtree|table_lifecycle|checkpoint)\.js$/, /^src\/table_lifecycle\//, /^src\/state_commitment\//, /^test\/unit\/(stateSubtreeActivation|contractStateSubtree|escrowLeafSubtree)\.test\.js$/, diff --git a/package-lock.json b/package-lock.json index f419064e..f242cfa6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "xchain-sync", - "version": "0.19.1", + "version": "0.20.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "xchain-sync", - "version": "0.19.1", + "version": "0.20.0", "license": "AGPL-3.0-or-later", "dependencies": { "acorn": "8.18.0", diff --git a/package.json b/package.json index 4fcbbe8f..a8cb859f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "xchain-sync", "description": "Database replication service for the XChain Platform: syncs indexer and decoder databases to validators and consumers via REST snapshots and WebSocket streaming", - "version": "0.19.1", + "version": "0.20.0", "license": "AGPL-3.0-or-later", "repository": { "type": "git", diff --git a/src/api.js b/src/api.js index 0df3d5fd..61dc862e 100644 --- a/src/api.js +++ b/src/api.js @@ -32,7 +32,7 @@ const http = require('http'); const WebSocket = require('ws'); const { rateLimit, ipKeyGenerator } = require('express-rate-limit'); const config = require('./config'); -const { computeArmedMapFingerprintV2 } = require('./consensus/armed_map/fingerprint_v2'); +const { computeArmedMapFingerprintV2 } = require('./consensus/armed_map/fingerprint'); const { carrierLogicDigest } = require('./health/carrier_logic'); const SyncService = require('./SyncService'); const Utility = require('./util'); @@ -47,7 +47,10 @@ const coins = require('./coins'); // instance is safe. See BlockHasher.computeIndexMapChecksum (NON-consensus). const statusUtil = new Utility(); -function consensusIdentityFields(){ const armedMapV2 = computeArmedMapFingerprintV2().hex; return { armed_map_fingerprint: armedMapV2, armed_map_fingerprint_v2: armedMapV2, armed_map_fingerprint_version: 2, carrier_logic_digest: carrierLogicDigest() }; } +// The armed-map identity every /health body carries: fingerprint v2 in the legacy field, +// the version that names the algorithm, and the logic digest beside it. The _v2 alias of +// the W1 to W4 window is gone since W5 (activation-registry C4). +function consensusIdentityFields(){ return { armed_map_fingerprint: computeArmedMapFingerprintV2().hex, armed_map_fingerprint_version: 2, carrier_logic_digest: carrierLogicDigest() }; } dotenv.config(); diff --git a/src/checkpoint.js b/src/checkpoint.js index 87698427..dfbfa9af 100644 --- a/src/checkpoint.js +++ b/src/checkpoint.js @@ -26,9 +26,15 @@ ********************************************************************/ const crypto = require('crypto'); -const eq = require('./equivocation_header.js'); -const swq = require('./stake_weighted_quorum.js'); -const ckpt = require('./checkpoint_commitment_activation.js'); +const eq = require('./consensus/equivocation_header.js'); +const swq = require('./consensus/stake_weighted_quorum.js'); +// The CHECKPOINT_COMMITMENT flag day is a registry row read by its literal key (W5); +// the predicate is activeAt over the checkpoint's BTC-anchored snapshot_block. +const { activeAt } = require('./consensus/gate_registry'); +const CHECKPOINT_COMMITMENT_KEY = 'checkpoint_commitment_activation.CHECKPOINT_COMMITMENT_ACTIVATION'; +function isCheckpointCommitmentActive(snapshotBlock, network){ + return activeAt(CHECKPOINT_COMMITMENT_KEY, network, null, snapshotBlock, null); +} // ASN.1 DER prefix for Ed25519 SPKI. Mirrors the hub's ValidatorIdentity and // the indexer's ed25519.js, so validator signatures verify identically here. @@ -49,7 +55,7 @@ function canonicalCheckpoint(cp){ // RAW string BEFORE the EQUIV wrap. The all-four-present guard keeps legacy null-root // rows on their original rootless canonical; post-flag-day the hub never signs a // rootless checkpoint, so it is always true for real rows. - if(ckpt.isCheckpointCommitmentActive(cp.snapshot_block, cp.network) && + if(isCheckpointCommitmentActive(cp.snapshot_block, cp.network) && cp.state_root != null && cp.block_merkle_root != null && cp.state_root_version != null && cp.block_merkle_version != null) raw += '|' + [String(cp.state_root).toLowerCase(), String(cp.state_root_version), @@ -81,7 +87,7 @@ function verifySignature(payload, sigHex, pubkeyHex){ // absent, which means the row cannot be verified at all: the canonical it would be // checked against is the legacy rootless one, not what a post-flag-day producer signs. function commitmentMissing(cp){ - if(!cp || !ckpt.isCheckpointCommitmentActive(cp.snapshot_block, cp.network)) return false; + if(!cp || !isCheckpointCommitmentActive(cp.snapshot_block, cp.network)) return false; return cp.state_root === null || cp.state_root === undefined || cp.block_merkle_root === null || cp.block_merkle_root === undefined || cp.state_root_version === null || cp.state_root_version === undefined diff --git a/src/checkpoint_commitment_activation.js b/src/checkpoint_commitment_activation.js deleted file mode 100644 index 8a3ba647..00000000 --- a/src/checkpoint_commitment_activation.js +++ /dev/null @@ -1,69 +0,0 @@ -/********************************************************************* - * - * Copyright ยฉ 2025โ€“2026 Dankest, LLC - * Based on XChain Platform by Dankest, LLC โ€“ https://dankest.llc - * - * SPDX-License-Identifier: AGPL-3.0-or-later - * - * This file is part of XChain Platform. Licensed under the GNU Affero - * General Public License v3.0 or later; see LICENSE.md. - * - ********************************************************************** - * - * Light-client checkpoint-commitment flag-day (SPV spec ยง6.1/ยง6.3, Phase 2). - * - * Gates when the quorum-signed checkpoint canonical (and the on-chain ANCHOR) - * begin COMMITTING the additive `state_root` + `block_merkle_root` (with their - * version bytes) that the Phase 1 STATE_COMMITMENT flag-day made the indexer - * compute. At/above this height the checkpoint signing string gains - * `|STATE_ROOT|STATE_ROOT_VERSION|BLOCK_MERKLE_ROOT|BLOCK_MERKLE_VERSION` and a - * new ANCHOR v3 carries the roots on DOGE; below it both keep their old shape and - * the roots are absent. Because it changes the SIGNED preimage of every checkpoint - * signature it is consensus-relevant and must deploy hub + ALL indexers + the - * SDK/explorer verifiers atomically. - * - * UNLIKE the Phase 1 state_commitment_activation (which gates on each chain's OWN - * local block_index), this gates on the BTC-anchored `snapshot_block` carried by - * every checkpoint canonical, exactly like stake_weighted_quorum / equivocation_ - * header, so every peer that evaluates it (the hub signer, the SDK/explorer/sync - * verifiers) flips the SIGNED shape on the same anchor. - * - * WHY THIS MODULE HAS NO CALL SITE IN THE INDEXER. Nothing under xchain-indexer/src - * calls isCheckpointCommitmentActive, because the indexer's own checkpoint-section - * canonical (src/actions/anchor.js, FORMAT 0) appends the root suffix - * UNCONDITIONALLY, alone among the four builders, so there is no height for this side - * to test. Parity rests instead on the producer-side invariant recorded at that call - * site (no bundle carries a section whose own snapshot block is below this height), - * which is a deployment fact rather than a code property and is fail-closed when it - * breaks: a section the hub signed rootless fails every section signature and the - * whole bundle is refused. The file stays here as the indexer's REGISTRATION of the - * consensus parameter, pinned to the canonical map by - * test/unit/activationConstantsParity.test.js and inventoried by - * src/consensus_rules_digest.js. - * - * LOCAL COPY of the canonical map in xchain-documentation/protocol/constants.js, - * kept byte-equal by the cross-service regression suite (a divergence forks the - * signed checkpoint and breaks federation quorum verification). Byte-identical twins - * live in xchain-{hub,sdk,explorer,sync}/src/checkpoint_commitment_activation.js. - * - ********************************************************************/ - -const { get, copy, activeAt } = require('./consensus/gate_registry'); - -const CHECKPOINT_COMMITMENT_ACTIVATION = copy('checkpoint_commitment_activation.CHECKPOINT_COMMITMENT_ACTIVATION'); - -// Whether the checkpoint/ANCHOR commits the light-client roots for a checkpoint -// whose BTC-anchored snapshot is at `snapshotBlock` on `network`. Below the -// threshold -> off (old canonical shape, no roots). Unknown network -> off (safe). -function isCheckpointCommitmentActive(snapshotBlock, network){ - let sb = parseInt(snapshotBlock); - if(!Number.isFinite(sb)) return false; - let threshold = CHECKPOINT_COMMITMENT_ACTIVATION[network]; - if(threshold === undefined) return false; - return sb >= threshold; -} - -module.exports = { - CHECKPOINT_COMMITMENT_ACTIVATION, - isCheckpointCommitmentActive -}; diff --git a/src/client/applier.js b/src/client/applier.js index ed7910cd..ae8d1e41 100644 --- a/src/client/applier.js +++ b/src/client/applier.js @@ -26,7 +26,7 @@ const { decodeValue } = require('../util/wire_codec'); const { rederiveEscrowGate } = require('./rollback'); const { generatedColumns } = require('../schema/generated_columns'); const { computeFollowerRoots, seedSnapshotRoots } = require('../state_commitment'); -const { isStateCommitmentActive, isStateCommitmentActivationBlock } = require('../state_commitment_activation'); +const { isStateCommitmentActive, isStateCommitmentActivationBlock } = require('../consensus/gates/state_commitment_gate'); const { coinTicker } = require('../consensus-constants'); const { OPERATOR_LOCAL_TABLES, SOURCE_UNSTREAMED_TABLES, orderSnapshotTables } = require('../server/snapshot_builder'); const lifecycle = require('../table_lifecycle'); diff --git a/src/client/block_hasher.js b/src/client/block_hasher.js index 342bb573..35b5ae71 100644 --- a/src/client/block_hasher.js +++ b/src/client/block_hasher.js @@ -55,10 +55,13 @@ const DEFAULT_CONTENT_PARITY_WINDOW = 100; const replicatedTables = require('../schema/replicated_tables'); const lifecycle = require('../table_lifecycle'); -const { buildStateHashData } = require('../stateHash'); +const { buildStateHashData } = require('../consensus/state_hash'); const { gasTickSymbol } = require('../consensus-constants'); const { canonicalizeHashAddress } = require('../util/protocol_address_roles'); -const { isStateKeyBinCollationActive } = require('../state_key_collation_activation'); +// The state-key binary collation flag day is a registry row read by literal key (W5), +// keyed ':' so the coin goes with the height. +const gateRegistry = require('../consensus/gate_registry'); +const STATE_KEY_COLLATION_KEY = 'state_key_collation_activation.STATE_KEY_COLLATION_ACTIVATION'; class BlockHasher { @@ -175,8 +178,8 @@ class BlockHasher { // state_key collation is flag-day gated, byte-for-byte mirror of // xchain-indexer/src/db/actions.js getBlockHashes(): legacy folding // (utf8_general_ci) below the activation height, COLLATE utf8_bin - // pinned at/after it (see state_key_collation_activation.js). - let stateKeyBin = isStateKeyBinCollationActive(block_index, network, coin); + // pinned at/after it (the state_key_collation_activation registry row). + let stateKeyBin = gateRegistry.activeAt(STATE_KEY_COLLATION_KEY, network, coin, block_index, null); let stateKeyCollate = stateKeyBin ? ' COLLATE utf8_bin' : ''; query = `SELECT cs.contract_index, cs.state_key, cs.state_value FROM contract_state cs diff --git a/src/client/rollback.js b/src/client/rollback.js index 78102fa8..61e861ee 100644 --- a/src/client/rollback.js +++ b/src/client/rollback.js @@ -26,8 +26,8 @@ const balanceHelpers = require('../db/balance_helpers'); const lifecycle = require('../table_lifecycle'); const replicatedTables = require('../schema/replicated_tables'); const { activationDelayBlocks, gasTickSymbol } = require('../consensus-constants'); -const { ARCHIVE_HEAD_VERSIONS_SQL } = require('../stateHash'); -const { archiveAuthorScopeJoin, ARCHIVE_ROLLBACK_AUTHOR_SCOPE_ACTIVATION } = require('../archive_rollback_author_scope_activation'); +const { ARCHIVE_HEAD_VERSIONS_SQL } = require('../consensus/state_hash'); +const { archiveAuthorScopeJoin, ARCHIVE_ROLLBACK_AUTHOR_SCOPE_ACTIVATION } = require('../consensus/gates/archive_rollback_author_scope_gate'); const util = require('node:util'); const { getLogger } = require('../observability'); const logger = getLogger(); diff --git a/src/client/sync.js b/src/client/sync.js index 03664e69..e4a6f30a 100644 --- a/src/client/sync.js +++ b/src/client/sync.js @@ -32,7 +32,7 @@ const zlib = require('zlib'); const fs = require('fs'); const path = require('path'); const validation = require('../util/validation'); -const trainActivation = require('../train_activation'); +const trainActivation = require('../consensus/gates/train_gate'); const BlockHasher = require('./block_hasher'); const replicatedTables = require('../schema/replicated_tables'); const tableLifecycle = require('../table_lifecycle'); diff --git a/src/consensus/armed_map/fingerprint_v2.js b/src/consensus/armed_map/fingerprint.js similarity index 100% rename from src/consensus/armed_map/fingerprint_v2.js rename to src/consensus/armed_map/fingerprint.js diff --git a/src/equivocation_header.js b/src/consensus/equivocation_header.js similarity index 98% rename from src/equivocation_header.js rename to src/consensus/equivocation_header.js index 6d262cda..48e11991 100644 --- a/src/equivocation_header.js +++ b/src/consensus/equivocation_header.js @@ -43,7 +43,7 @@ * ********************************************************************/ -const { get, copy, activeAt } = require('./consensus/gate_registry'); +const { get, copy, activeAt } = require('./gate_registry'); const EQUIV_HEADER_ACTIVATION = copy('equivocation_header.EQUIV_HEADER_ACTIVATION'); diff --git a/src/consensus/gate_registry/shared_rows_1.js b/src/consensus/gate_registry/shared_rows_1.js index 59c78a94..bf311be0 100644 --- a/src/consensus/gate_registry/shared_rows_1.js +++ b/src/consensus/gate_registry/shared_rows_1.js @@ -295,7 +295,11 @@ addGate('anchor_reward_activation.ANCHOR_ATTEST_ARRIVAL_MARGIN_S', 'constant', 6 // that window. addGate('anchor_reward_activation.ANCHOR_ATTEST_BARRIER_ACTIVATION', 'height', { mainnet: null, // INERT under the 2026-08-29 mainnet write hold - testnet: null, // SIZED AT THE CUT from the measured tip plus the roll window + // SIZED 2026-09-16 20:41Z, on the BTC clock because this member is BTC-only: the same + // instant as the family's BTC CONSUMER height, so the one member that keeps BOTH + // certificates gains them together rather than carrying a lone extra rule for 6 h. + // Above the same roll and the same epoch close; the canon carries the measurement. + testnet: 153266, regtest: UNPINNED, // shares the family's arming seam so one venue lever arms both }); diff --git a/src/consensus/gate_registry/shared_rows_2.js b/src/consensus/gate_registry/shared_rows_2.js index 3b03a0b4..c7fd765d 100644 --- a/src/consensus/gate_registry/shared_rows_2.js +++ b/src/consensus/gate_registry/shared_rows_2.js @@ -204,19 +204,21 @@ addGate('mirror_admission_activation.ADMIT_MAX_FUTURE_BLOCKS', 'constant', { * height on a BTC indexer, so the two legs of one cross-chain match would cross the flag day at * unrelated instants. The 'COIN:network' key shape is established precedent. * - * Mainnet is null under the 2026-08-29 write hold. Testnet is sized at the release cut from the - * measured tip plus the roll window plus slack, per key. The v7 HUB_SCHEMA_VERSION roll - * completes BEFORE any network's activation height: the heights map rides frames carrying no - * schema_version, so a v7 indexer above the activation against a v6 hub would see no heights at - * all and defer forever under the fail-closed rule. + * Mainnet is null under the 2026-08-29 write hold. TESTNET SIZED 2026-09-16 20:41Z, LTC and DOGE + * RE-CUT 2026-09-17 22:45Z onto the BTC instant after their cadences drifted off it; the measured + * tips, the formula, the cadence-window rule, the epoch-close rule and the per-chain re-size rule + * are written once in the canon (xchain-documentation/protocol/constants.js), which this row is + * held value-identical to. The v7 HUB_SCHEMA_VERSION roll completes BEFORE any of these heights: + * the heights map rides frames carrying no schema_version, so a v7 indexer above the activation + * against a v6 hub would see no heights at all and defer forever under the fail-closed rule. */ addGate('mirror_admission_activation.MIRROR_ADMISSION_ACTIVATION', 'height', { 'BTC:mainnet': null, 'LTC:mainnet': null, 'DOGE:mainnet': null, - 'BTC:testnet': null, // SIZED AT THE CUT, strictly below the consumer height for this key - 'LTC:testnet': null, - 'DOGE:testnet': null, + 'BTC:testnet': 153222, // SIZED 2026-09-16 20:41Z: epoch close 153,216 + 6 buried; tip 152,756 + 466 at 498.7 s/blk, about 64.5 h + 'LTC:testnet': 4891504, // RE-CUT 2026-09-17 22:45Z onto that instant: tip 4,889,190 + 2314 at 82.5 s/blk + 'DOGE:testnet': 67911796, // RE-CUT 2026-09-17 22:45Z onto that instant: tip 67,904,912 + 6884 at 27.7 s/blk 'BTC:regtest': UNPINNED, // ARMS by XC_MIRROR_ADMISSION_ACTIVATION at registration 'LTC:regtest': UNPINNED, // ARMS by XC_MIRROR_ADMISSION_ACTIVATION at registration 'DOGE:regtest': UNPINNED, // ARMS by XC_MIRROR_ADMISSION_ACTIVATION at registration @@ -226,9 +228,9 @@ addGate('mirror_admission_activation.MIRROR_ADMISSION_CONSUMER_ACTIVATION', 'hei 'BTC:mainnet': null, 'LTC:mainnet': null, 'DOGE:mainnet': null, - 'BTC:testnet': null, // SIZED AT THE CUT, strictly above the producer height for this key - 'LTC:testnet': null, - 'DOGE:testnet': null, + 'BTC:testnet': 153266, // its producer + 44 blocks, about 6 h: strictly above, never equal + 'LTC:testnet': 4891766, // its producer + 262 blocks, about 6 h at 82.5 s/blk + 'DOGE:testnet': 67912575, // its producer + 779 blocks, about 6 h at 27.7 s/blk 'BTC:regtest': UNPINNED, // ARMS by XC_MIRROR_ADMISSION_ACTIVATION at registration 'LTC:regtest': UNPINNED, // ARMS by XC_MIRROR_ADMISSION_ACTIVATION at registration 'DOGE:regtest': UNPINNED, // ARMS by XC_MIRROR_ADMISSION_ACTIVATION at registration diff --git a/src/consensus/gate_registry/shared_rows_5.js b/src/consensus/gate_registry/shared_rows_5.js index 92f3979b..cbf28976 100644 --- a/src/consensus/gate_registry/shared_rows_5.js +++ b/src/consensus/gate_registry/shared_rows_5.js @@ -97,6 +97,20 @@ addGate('train_activation.TRAIN_ACTIVATION', 'ruleset', { // bridge height below sits above it on the same BTC clock, so a node lacking this rule // set halts before it can grade a bridge action. '0.19.0': { mainnet: 9999999999, testnet: 152787, regtest: 0 }, + // The mirror-admission rule set, armed at the v0.20.0 cut: the producer and consumer + // admission maps and the anchor-attest barrier replace the effective_time binding, so a + // node without them grades an admission-stamped row under the rule it replaced. Mainnet + // holds the house sentinel because the whole family is null on mainnet under the + // 2026-08-29 write hold. Testnet: SIZED 2026-09-17 22:45Z, chain_tip TBTC 152,891 + 225 + // blocks, which is ceil(36 h / 576.7 s per block), about 36.0 h. The cadence is measured + // over a trailing window as long as the lead being sized (53 h here), never the last 99 + // blocks: a 99-block window on a testnet difficulty burst is noise, and it is what pulled + // the LTC leg of this family two days off its BTC counterpart a day after the first cut. + // That lead is the rolling-upgrade window the fleet roll must finish inside (24x the 90 + // minute roll budget), and every testnet mirror-admission height sits above it on the same + // BTC clock (the BTC producer at 153,222 is 106 blocks and about 17.0 h further up), so a + // node lacking this rule set halts before it can grade an admission-stamped row. + '0.20.0': { mainnet: 9999999999, testnet: 153116, regtest: 0 }, }); // xchain_bridge_activation diff --git a/src/archive_rollback_author_scope_activation.js b/src/consensus/gates/archive_rollback_author_scope_gate.js similarity index 98% rename from src/archive_rollback_author_scope_activation.js rename to src/consensus/gates/archive_rollback_author_scope_gate.js index 271f16d3..811af83d 100644 --- a/src/archive_rollback_author_scope_activation.js +++ b/src/consensus/gates/archive_rollback_author_scope_gate.js @@ -64,7 +64,7 @@ 'use strict'; -const { get, copy, activeAt } = require('./consensus/gate_registry'); +const { get, copy, activeAt } = require('../gate_registry'); const ARCHIVE_ROLLBACK_AUTHOR_SCOPE_ACTIVATION = copy('archive_rollback_author_scope_activation.ARCHIVE_ROLLBACK_AUTHOR_SCOPE_ACTIVATION'); diff --git a/src/stake_weight_collation_activation.js b/src/consensus/gates/stake_weight_collation_gate.js similarity index 99% rename from src/stake_weight_collation_activation.js rename to src/consensus/gates/stake_weight_collation_gate.js index 8ac4ecde..c33c3ea4 100644 --- a/src/stake_weight_collation_activation.js +++ b/src/consensus/gates/stake_weight_collation_gate.js @@ -61,7 +61,7 @@ * ********************************************************************/ -const { get, copy, activeAt } = require('./consensus/gate_registry'); +const { get, copy, activeAt } = require('../gate_registry'); const STAKE_WEIGHT_COLLATION = copy('stake_weight_collation_activation.STAKE_WEIGHT_COLLATION'); diff --git a/src/state_commitment_activation.js b/src/consensus/gates/state_commitment_gate.js similarity index 97% rename from src/state_commitment_activation.js rename to src/consensus/gates/state_commitment_gate.js index 1c3e8b85..4e5f9416 100644 --- a/src/state_commitment_activation.js +++ b/src/consensus/gates/state_commitment_gate.js @@ -31,7 +31,7 @@ * ********************************************************************/ -const { get, copy, activeAt } = require('./consensus/gate_registry'); +const { get, copy, activeAt } = require('../gate_registry'); const STATE_COMMITMENT_ACTIVATION = copy('state_commitment_activation.STATE_COMMITMENT_ACTIVATION'); diff --git a/src/state_subtree_activation.js b/src/consensus/gates/state_subtree_gate.js similarity index 99% rename from src/state_subtree_activation.js rename to src/consensus/gates/state_subtree_gate.js index af1205da..46e85520 100644 --- a/src/state_subtree_activation.js +++ b/src/consensus/gates/state_subtree_gate.js @@ -84,7 +84,7 @@ 'use strict'; -const { get, copy, activeAt } = require('./consensus/gate_registry'); +const { get, copy, activeAt } = require('../gate_registry'); const RESERVED_SUBTREES = copy('state_subtree_activation.RESERVED_SUBTREES'); diff --git a/src/swq_source_cap_activation.js b/src/consensus/gates/swq_source_cap_gate.js similarity index 98% rename from src/swq_source_cap_activation.js rename to src/consensus/gates/swq_source_cap_gate.js index c9edfda9..bfd0b4fb 100644 --- a/src/swq_source_cap_activation.js +++ b/src/consensus/gates/swq_source_cap_gate.js @@ -44,7 +44,7 @@ * ********************************************************************/ -const { get, copy, activeAt } = require('./consensus/gate_registry'); +const { get, copy, activeAt } = require('../gate_registry'); const STAKE_WEIGHT_MAX_SOURCES = copy('swq_source_cap_activation.STAKE_WEIGHT_MAX_SOURCES'); const STAKE_WEIGHT_MAX_KEYS_PER_SOURCE = copy('swq_source_cap_activation.STAKE_WEIGHT_MAX_KEYS_PER_SOURCE'); diff --git a/src/train_activation.js b/src/consensus/gates/train_gate.js similarity index 99% rename from src/train_activation.js rename to src/consensus/gates/train_gate.js index 405a3c56..de040450 100644 --- a/src/train_activation.js +++ b/src/consensus/gates/train_gate.js @@ -70,7 +70,7 @@ 'use strict'; -const { get, copy, activeAt } = require('./consensus/gate_registry'); +const { get, copy, activeAt } = require('../gate_registry'); const TRAIN_ACTIVATION = copy('train_activation.TRAIN_ACTIVATION'); diff --git a/src/stake_weighted_quorum.js b/src/consensus/stake_weighted_quorum.js similarity index 99% rename from src/stake_weighted_quorum.js rename to src/consensus/stake_weighted_quorum.js index 493d7f11..76fdd4ed 100644 --- a/src/stake_weighted_quorum.js +++ b/src/consensus/stake_weighted_quorum.js @@ -32,7 +32,7 @@ * ********************************************************************/ -const { get, copy, activeAt } = require('./consensus/gate_registry'); +const { get, copy, activeAt } = require('./gate_registry'); const mathjs = require('mathjs'); diff --git a/src/stateHash.js b/src/consensus/state_hash.js similarity index 99% rename from src/stateHash.js rename to src/consensus/state_hash.js index c3ffd493..5f736485 100644 --- a/src/stateHash.js +++ b/src/consensus/state_hash.js @@ -54,7 +54,7 @@ * ********************************************************************/ -const { get, copy, activeAt } = require('./consensus/gate_registry'); +const { get, copy, activeAt } = require('./gate_registry'); const STATE_HASH_VERSION = copy('stateHash.STATE_HASH_VERSION'); diff --git a/src/db/actions.js b/src/db/actions.js index cba59ade..8827885f 100644 --- a/src/db/actions.js +++ b/src/db/actions.js @@ -22,7 +22,10 @@ const path = require('path'); const { canonicalizeHashAddress } = require('../util/protocol_address_roles'); -const { isStateKeyBinCollationActive } = require('../state_key_collation_activation'); +// The state-key binary collation flag day is a registry row read by literal key (W5), +// keyed ':' so the coin goes with the height. +const gateRegistry = require('../consensus/gate_registry'); +const STATE_KEY_COLLATION_KEY = 'state_key_collation_activation.STATE_KEY_COLLATION_ACTIVATION'; const lifecycle = require('../table_lifecycle'); const { assertValidIdentifier } = require('./shared.js'); @@ -93,7 +96,7 @@ module.exports = { escrows: `SELECT e.action_index, a1.address AS address, t1.tick AS tick, e.amount FROM escrows e INNER JOIN actions a ON (a.action_index=e.action_index) LEFT JOIN index_addresses a1 ON (a1.id=e.address_id) LEFT JOIN index_tickers t1 ON (t1.id=e.tick_id) WHERE a.block_index=? ORDER BY e.action_index ASC, a1.address COLLATE utf8_bin ASC, t1.tick COLLATE utf8mb4_bin ASC, e.amount ASC` }); let actions = await this.doQueryStrict(`SELECT a.action_index, a.tx_index, ia.action AS action FROM actions a LEFT JOIN index_actions ia ON (ia.id=a.action_id) WHERE a.block_index=? ORDER BY a.action_index ASC`, [block_index], conn); - let stateKeyCollate = isStateKeyBinCollationActive(block_index, network, coin) ? ' COLLATE utf8_bin' : ''; + let stateKeyCollate = gateRegistry.activeAt(STATE_KEY_COLLATION_KEY, network, coin, block_index, null) ? ' COLLATE utf8_bin' : ''; let contracts = await getContractLeafRows(this, block_index, conn, stateKeyCollate, { contracts: `SELECT c.action_index, a1.address AS source_address, c.code_hash, s1.status AS status FROM contracts c INNER JOIN actions a ON (a.action_index=c.action_index) LEFT JOIN index_addresses a1 ON (a1.id=c.source_id) LEFT JOIN index_statuses s1 ON (s1.id=c.status_id) WHERE a.block_index=? ORDER BY c.action_index ASC`, statePrefix: `SELECT cs.contract_index, cs.state_key, cs.state_value FROM contract_state cs INNER JOIN ( SELECT MAX(id) as max_id FROM contract_state WHERE block_index=? GROUP BY contract_index, state_key`, diff --git a/src/db/index.js b/src/db/index.js index 61508936..0209ee8f 100644 --- a/src/db/index.js +++ b/src/db/index.js @@ -35,7 +35,7 @@ const path = require('path'); const validation = require('../util/validation'); const { splitSqlStatements } = require('./sql_util'); const poolSizing = require('./pool_sizing'); -const stakeWeightCollation = require('../stake_weight_collation_activation'); +const stakeWeightCollation = require('../consensus/gates/stake_weight_collation_gate'); const utf8mb4Columns = require('../schema/utf8mb4_columns'); const lifecycle = require('../table_lifecycle'); diff --git a/src/db/stakes.js b/src/db/stakes.js index a38601e3..4ad2a98c 100644 --- a/src/db/stakes.js +++ b/src/db/stakes.js @@ -22,8 +22,8 @@ ********************************************************************/ const path = require('path'); -const swqCap = require('../swq_source_cap_activation'); -const stakeWeightCollation = require('../stake_weight_collation_activation'); +const swqCap = require('../consensus/gates/swq_source_cap_gate'); +const stakeWeightCollation = require('../consensus/gates/stake_weight_collation_gate'); const { requireStakeWeight } = require('./shared.js'); const { getLogger } = require('../observability'); const logger = getLogger(); diff --git a/src/schema/utf8mb4_columns.js b/src/schema/utf8mb4_columns.js index 8c79312e..44cd0104 100644 --- a/src/schema/utf8mb4_columns.js +++ b/src/schema/utf8mb4_columns.js @@ -72,7 +72,7 @@ * preimage queries and the stake-weight collation guard, so it is its own ruling and * its own change, the way state_key already is. * * contract_state.state_key / state_key_bin / state_value - the state_key collation is - * a height-gated consensus flag-day (src/state_key_collation_activation.js). + * a height-gated consensus flag-day (the state_key_collation_activation registry row). * * polls.callback_params - its ADD COLUMN migration (2026-07-05) is checksum-immutable * and declares plain MEDIUMTEXT, so a charset on the definition would break the * ADD-COLUMN parity gate with no legal way to converge the two paths. diff --git a/src/server/poller.js b/src/server/poller.js index 29073ec7..e26bf452 100644 --- a/src/server/poller.js +++ b/src/server/poller.js @@ -35,7 +35,7 @@ const { collectMaturedCooldownCredits } = require('./cooldown_credits'); const { collectRedrivenValidatorRewards } = require('./recovery_rewards'); const { collectDerivedAnchorRewards } = require('./derived_rewards'); const { activationDelayBlocks, coinTicker } = require('../consensus-constants'); -const { isStateCommitmentActive } = require('../state_commitment_activation'); +const { isStateCommitmentActive } = require('../consensus/gates/state_commitment_gate'); const { SCHEMA_VERSION } = require('../schema/version'); const util = require('node:util'); const { getLogger } = require('../observability'); diff --git a/src/server/updated_rows.js b/src/server/updated_rows.js index 90767dcd..dbbab58e 100644 --- a/src/server/updated_rows.js +++ b/src/server/updated_rows.js @@ -80,7 +80,7 @@ * ********************************************************************/ -const { ARCHIVE_HEAD_VERSIONS_SQL, ARCHIVE_CHUNK_HEIGHT_COL } = require('../stateHash'); +const { ARCHIVE_HEAD_VERSIONS_SQL, ARCHIVE_CHUNK_HEIGHT_COL } = require('../consensus/state_hash'); const { DEACTIVATION_TABLES, SLASH_SPECS, ROTATION_TABLES, REQUEST_STATUS_TABLES, POLL_FINALIZE_TABLES, COOLDOWN_STATUS_TABLES, ATTEST_BATCH_HEAD_VERSION, diff --git a/src/state_commitment/index.js b/src/state_commitment/index.js index 26d90ff8..d5b672ae 100644 --- a/src/state_commitment/index.js +++ b/src/state_commitment/index.js @@ -66,7 +66,7 @@ const M = require('../merkle.js'); const CC = require('../consensus-constants.js'); -const SUB = require('../state_subtree_activation.js'); +const SUB = require('../consensus/gates/state_subtree_gate.js'); const CST = require('../contract_state_subtree.js'); const ESC = require('../escrow_leaf_subtree.js'); const { minimalDecimal } = require('../db/balance_helpers.js'); diff --git a/src/state_key_collation_activation.js b/src/state_key_collation_activation.js deleted file mode 100644 index 5fd1febb..00000000 --- a/src/state_key_collation_activation.js +++ /dev/null @@ -1,85 +0,0 @@ -/********************************************************************* - * - * Copyright ยฉ 2025โ€“2026 Dankest, LLC - * Based on XChain Platform by Dankest, LLC โ€“ https://dankest.llc - * - * SPDX-License-Identifier: AGPL-3.0-or-later - * - * This file is part of XChain Platform. Licensed under the GNU Affero - * General Public License v3.0 or later; see LICENSE.md. - * - ********************************************************************** - * - * Contract-state `state_key` binary-collation flag-day. - * - * The contract_state table is declared CHARSET=utf8 COLLATE=utf8_general_ci - * (case- AND accent-folding), so the two consensus-facing readers that - * GROUP BY / ORDER BY `state_key` treat DISTINCT keys a contract legitimately - * writes (e.g. "Key" vs "key" - the VM's StateManager is Object.create(null) - * precisely so adversarial keys round-trip) as EQUAL: - * - * 1. db.getBlockHashes() / xchain-sync BlockHasher.computeBlockHashes(): - * the per-block contract-state rows feeding the consensus contract_hash. - * Folding GROUP BY collapses collation-equal distinct keys to one group - * and keeps only MAX(id), so one written key's latest value is silently - * ABSENT from the hash preimage (state that consensus does not cover), - * and a snapshot-bootstrapped follower whose physical id assignment - * differs can keep the OTHER collision row - divergent contract_hash for - * identical history. Every other consensus sort in the same function - * already pins a binary collation for exactly this hazard (address - * COLLATE utf8_bin, tick COLLATE utf8mb4_bin); state_key was the one - * column left folding. - * 2. db.getContractState(): the VM state reload before EXECUTE. The folding - * GROUP BY drops one of two collation-equal keys on reload, so the key - * vanishes on the next EXECUTE, contradicting the adversarial-key - * round-trip contract of the null-prototype state object. - * - * The fix pins `state_key COLLATE utf8_bin` in those GROUP BY / ORDER BY - * clauses. Binary collation changes both the grouping (collation-colliding - * keys stop collapsing) and the sort order (case-folded vs binary order) of - * the contract_hash preimage, and changes what a reloaded contract sees, so - * an ungated flip re-evaluates already-valid blocks differently and FORKS - * against deployed nodes. It is therefore height-gated per chain, exactly - * like state_commitment_activation.js / swq_source_cap_activation.js: below - * the chain's activation height the legacy folding queries run (historical - * replay stays byte-identical); at/after it the binary-collation queries run. - * - * Gate semantics MIRROR state_commitment_activation.js: keyed on the - * processing chain's OWN local `block_index`, ':' lookup - * first, then the bare network key; unknown -> inert/off (legacy folding - * path, which preserves deployed behavior). - * - * The byte-identical twin lives in xchain-sync/src/ (BlockHasher is the - * byte-for-byte conformance pair of getBlockHashes); the xchain-sync twin - * guard (test/unit/rollback-coverage.test.js) locks the two files equal. - * BOTH repos must deploy fleet-wide before any armed height is reached. - * - ********************************************************************/ - -const { get, copy, activeAt } = require('./consensus/gate_registry'); - -const STATE_KEY_COLLATION_ACTIVATION = copy('state_key_collation_activation.STATE_KEY_COLLATION_ACTIVATION'); - -// Resolve the per-chain threshold: ':' key first, then the bare -// network key (regtest keeps one key). Unknown -> undefined -> inert/off. -function _activationThreshold(network, coin){ - if(coin != null && STATE_KEY_COLLATION_ACTIVATION[coin + ':' + network] !== undefined) - return STATE_KEY_COLLATION_ACTIVATION[coin + ':' + network]; - return STATE_KEY_COLLATION_ACTIVATION[network]; -} - -// Whether the binary `state_key` collation is in effect at `blockIndex` on -// `network` for `coin`. Below the threshold / unknown chain -> off (legacy -// folding queries, byte-identical historical replay). -function isStateKeyBinCollationActive(blockIndex, network, coin){ - let b = parseInt(blockIndex); - if(!Number.isFinite(b)) return false; - let threshold = _activationThreshold(network, coin); - if(threshold === undefined) return false; - return b >= threshold; -} - -module.exports = { - STATE_KEY_COLLATION_ACTIVATION, - isStateKeyBinCollationActive -}; diff --git a/test/fixtures/gen-state-hash-vectors.js b/test/fixtures/gen-state-hash-vectors.js index 7aae91dc..ab802744 100644 --- a/test/fixtures/gen-state-hash-vectors.js +++ b/test/fixtures/gen-state-hash-vectors.js @@ -30,7 +30,7 @@ const path = require('path'); process.env.INDEXER_COIN = process.env.INDEXER_COIN || 'BTC'; process.env.INDEXER_NETWORK = process.env.INDEXER_NETWORK || 'regtest'; -const { buildStateHashData } = require('../../src/stateHash'); +const { buildStateHashData } = require('../../src/consensus/state_hash'); const IndexerUtil = require('../../../xchain-indexer/src/utility.js'); const BLOCK_INDEX = 1000; diff --git a/test/integration/subtree_armed_follower.test.js b/test/integration/subtree_armed_follower.test.js index 22bf8463..ca41f57c 100644 --- a/test/integration/subtree_armed_follower.test.js +++ b/test/integration/subtree_armed_follower.test.js @@ -40,7 +40,7 @@ const fixtures = require('./helpers/fixtures'); const ServerPoller = require('../../src/server/poller'); const ClientApplier = require('../../src/client/applier'); const ClientRollback = require('../../src/client/rollback'); -const SUB = require('../../src/state_subtree_activation'); +const SUB = require('../../src/consensus/gates/state_subtree_gate'); const SC = require('../../src/state_commitment'); const CHAIN = 'litecoin'; diff --git a/test/integration/subtree_shadow_cross_twin.test.js b/test/integration/subtree_shadow_cross_twin.test.js index 5a6d38a1..880108a2 100644 --- a/test/integration/subtree_shadow_cross_twin.test.js +++ b/test/integration/subtree_shadow_cross_twin.test.js @@ -45,7 +45,7 @@ const fixtures = require('./helpers/fixtures'); const ServerPoller = require('../../src/server/poller'); const ClientApplier = require('../../src/client/applier'); -const SUB = require('../../src/state_subtree_activation'); +const SUB = require('../../src/consensus/gates/state_subtree_gate'); const CST = require('../../src/contract_state_subtree'); const SC = require('../../src/state_commitment'); diff --git a/test/unit/checkpoint_commitment_activation.test.js b/test/unit/checkpoint_commitment_activation.test.js deleted file mode 100644 index 55fe3da8..00000000 --- a/test/unit/checkpoint_commitment_activation.test.js +++ /dev/null @@ -1,42 +0,0 @@ -// doctrine test-coverage program: unit coverage for -// src/checkpoint_commitment_activation.js. This is a byte-identical twin of the -// hub/indexer/sdk/explorer copies; it gates the SIGNED checkpoint preimage on -// the BTC-anchored snapshot_block, so the threshold map and the gate function -// must stay pinned or federation quorum verification forks. - -const assert = require('assert'); -const { - CHECKPOINT_COMMITMENT_ACTIVATION, isCheckpointCommitmentActive, -} = require('../../src/checkpoint_commitment_activation.js'); - -describe('checkpoint_commitment_activation', function () { - it('exposes a per-network threshold map with regtest armed from genesis', function () { - assert.strictEqual(CHECKPOINT_COMMITMENT_ACTIVATION.regtest, 0); - // Regression note (lead 0e418c8c): testnet was 0, which made the hub commit the SPV - // root suffix from testnet genesis before the indexer had roots to sign, - // so it refused to sign every testnet checkpoint. Now armed at the first - // BTC-testnet anchor past all three STATE_COMMITMENT testnet thresholds. - assert.strictEqual(CHECKPOINT_COMMITMENT_ACTIVATION.testnet, 146000); - // Pin the exact ARMED mainnet flag-day (BTC anchor ~2026-08-04). A loose - // `> 0` let a one-sided edit of any vendored copy pass green while moving - // the block at which every validator starts committing the light-client - // roots into the signed checkpoint. - assert.strictEqual(CHECKPOINT_COMMITMENT_ACTIVATION.mainnet, 961000); - }); - - it('activates at/above the mainnet threshold and is off below it', function () { - const t = CHECKPOINT_COMMITMENT_ACTIVATION.mainnet; - assert.strictEqual(isCheckpointCommitmentActive(t, 'mainnet'), true); - assert.strictEqual(isCheckpointCommitmentActive(t - 1, 'mainnet'), false); - }); - - it('testnet arms at 146000, off one block below (keying-skew fix)', function () { - assert.strictEqual(isCheckpointCommitmentActive(146000, 'testnet'), true); - assert.strictEqual(isCheckpointCommitmentActive(145999, 'testnet'), false); - }); - - it('fails closed on malformed input and unknown networks', function () { - assert.strictEqual(isCheckpointCommitmentActive('nope', 'mainnet'), false); - assert.strictEqual(isCheckpointCommitmentActive(999999999, 'no-such-net'), false); - }); -}); diff --git a/test/unit/checkpoint_twin.test.js b/test/unit/checkpoint_twin.test.js index b9310c34..b5c41f73 100644 --- a/test/unit/checkpoint_twin.test.js +++ b/test/unit/checkpoint_twin.test.js @@ -10,8 +10,9 @@ * ********************************************************************** * Vendored checkpoint verifier conformance. src/checkpoint.js (+ its - * stake_weighted_quorum / equivocation_header / checkpoint_commitment_activation - * siblings) is a byte-identical TWIN of the xchain-sdk copies. This guards that + * consensus/stake_weighted_quorum and consensus/equivocation_header siblings; the + * CHECKPOINT_COMMITMENT flag day is a registry row) is a code-identical TWIN of the + * xchain-sdk copies. This guards that * the vendored copy actually verifies a real federation-signed checkpoint and * rejects a tampered one, so drift from the SDK is caught here rather than in * production (mirrors how merkle.js is golden-vector guarded). @@ -30,8 +31,7 @@ const SYNC_SRC = path.join(__dirname, '../../src'); const SDK_SRC = path.join(__dirname, '../../../xchain-sdk/src'); const SIBLING_REQUIRED = process.env.XCHAIN_REQUIRE_SIBLINGS === '1'; // The four files this suite's header declares twins of the SDK copies. -const TWINS = ['checkpoint.js', 'stake_weighted_quorum.js', 'equivocation_header.js', - 'checkpoint_commitment_activation.js']; +const TWINS = ['checkpoint.js', 'consensus/stake_weighted_quorum.js', 'consensus/equivocation_header.js']; // Cut unquoted // comments (tracking ' " ` quote state per line) so the two // sides compare on CODE. The prose is independently worded in both copies and diff --git a/test/unit/client_sync_checkpoint_quorum.test.js b/test/unit/client_sync_checkpoint_quorum.test.js index 00acb1f9..3db234bc 100644 --- a/test/unit/client_sync_checkpoint_quorum.test.js +++ b/test/unit/client_sync_checkpoint_quorum.test.js @@ -157,7 +157,7 @@ describe('ClientSync: checkpoint-quorum anchor @regression', function(){ // uuid:c9dfc3d9. Deciding "pre-commitment" from the WIRE's missing state_root alone // lets a rootless checkpoint served AT an active height return before the // seq-regression and freshness guards below without a trace. The replica - // bundles the flag-day map (checkpoint_commitment_activation.js) and the verifier + // reads the flag-day row (checkpoint_commitment_activation, a registry row) and the verifier // already fail-closes on the same predicate, so the activation question is decided // locally. Regtest's threshold is 0, so every checkpoint here is commitment-active. it('WARNS on a rootless checkpoint at a commitment-ACTIVE height (does not anchor, does not halt)', async function(){ diff --git a/test/unit/coin_ticker_activation.test.js b/test/unit/coin_ticker_activation.test.js index baf09479..5fdd6977 100644 --- a/test/unit/coin_ticker_activation.test.js +++ b/test/unit/coin_ticker_activation.test.js @@ -32,7 +32,7 @@ const assert = require('assert'); const { coinTicker } = require('../../src/consensus-constants'); -const { isStateCommitmentActive } = require('../../src/state_commitment_activation'); +const { isStateCommitmentActive } = require('../../src/consensus/gates/state_commitment_gate'); describe('coinTicker() + per-chain activation lookup', function () { diff --git a/test/unit/consensus/armed_map/completeness.test.js b/test/unit/consensus/armed_map/completeness.test.js index 3d46b92a..ebe9cad1 100644 --- a/test/unit/consensus/armed_map/completeness.test.js +++ b/test/unit/consensus/armed_map/completeness.test.js @@ -26,7 +26,13 @@ const { ENTRIES, EXPECTED_KEYS, collectRows } = require(path.join(SRC, 'consensu const { KEY_RE } = require(path.join(SRC, 'consensus/armed_map/canonical')); const registry = require(path.join(SRC, 'consensus/gate_registry')); -/** {file: Set(registry keys)} for every shim under srcDir. */ +/** + * {file: Set(registry keys)} for every module under srcDir that reads the + * registry by a literal key: the get() and copy() calls of the shims, and the + * `const _KEY = ''` a W5 caller of a retired predicate-only shim + * spells beside its activeAt read (checkpoint.js, db/actions.js, + * client/block_hasher.js), so the two rows those shims carried stay counted. + */ function scanShims(srcDir) { const shims = new Map(); (function walk(dir, rel) { @@ -36,7 +42,8 @@ function scanShims(srcDir) { if (e.isDirectory()) { walk(path.join(dir, e.name), r); continue; } if (!e.name.endsWith('.js')) continue; const text = fs.readFileSync(path.join(dir, e.name), 'utf8'); - const keys = new Set(Array.from(text.matchAll(/\b(?:get|copy)\(['"]([^'"]+)['"]\)/g), (m) => m[1])); + const keys = new Set(Array.from(text.matchAll(/\b(?:get|copy)\(['"]([^'"]+)['"]\)/g), (m) => m[1]) + .concat(Array.from(text.matchAll(/\bconst\s+[A-Z0-9_]+_KEY\s*=\s*['"]([^'"]+)['"]/g), (m) => m[1]))); if (keys.size && text.includes('gate_registry')) shims.set(r, keys); } })(srcDir, ''); @@ -50,7 +57,9 @@ const manifestKeys = ENTRIES.map(([key]) => key); describe('armed map v2: manifest completeness over src/', function () { it('the shim scan finds all twelve gate files and all 39 rows', function () { - assert.strictEqual(shims.size, 12, 'the shim scan found ' + shims.size + ' files'); + // 10 shims (6 gates, 3 carriers, consensus-constants) plus the three W5 + // callers that read a retired predicate-only shim's row by literal key. + assert.strictEqual(shims.size, 13, 'the shim scan found ' + shims.size + ' files'); assert.strictEqual(shimKeys.size, 39, 'the shim scan found ' + shimKeys.size + ' keys'); }); diff --git a/test/unit/consensus/armed_map/falsification.test.js b/test/unit/consensus/armed_map/falsification.test.js index 86a75a9d..30f93284 100644 --- a/test/unit/consensus/armed_map/falsification.test.js +++ b/test/unit/consensus/armed_map/falsification.test.js @@ -59,7 +59,7 @@ function edit(root, rel, from, to) { } function readV2(root, env) { - const res = spawnSync(process.execPath, ['-e', READ_V2, path.join(root, 'src/consensus/armed_map/fingerprint_v2.js')], + const res = spawnSync(process.execPath, ['-e', READ_V2, path.join(root, 'src/consensus/armed_map/fingerprint.js')], { cwd: root, encoding: 'utf8', env: cleanEnv(env) }); assert.strictEqual(res.status, 0, res.stderr); return JSON.parse(res.stdout); @@ -98,7 +98,7 @@ describe('armed map v2: falsification on temp trees', function () { after(removeTrees); it('a copied tree reads the same v2 as this checkout, so the harness measures the real thing', function () { - const { computeArmedMapFingerprintV2 } = require(path.join(ROOT, 'src/consensus/armed_map/fingerprint_v2')); + const { computeArmedMapFingerprintV2 } = require(path.join(ROOT, 'src/consensus/armed_map/fingerprint')); assert.strictEqual(baseline.hex, computeArmedMapFingerprintV2().hex); }); @@ -124,12 +124,12 @@ describe('armed map v2: falsification on temp trees', function () { it('holds under a comment, a registry reformat, a carrier rename and a move', function () { const root = tree(); - fs.appendFileSync(path.join(root, 'src/stateHash.js'), '\n// a carrier comment\n'); + fs.appendFileSync(path.join(root, 'src/consensus/state_hash.js'), '\n// a carrier comment\n'); edit(root, 'src/consensus/gate_registry/shared_rows_2.js', ' testnet: 146000,', ' testnet: 146000,'); - fs.renameSync(path.join(root, 'src/train_activation.js'), path.join(root, 'src/rule_set_train.js')); + fs.renameSync(path.join(root, 'src/consensus/gates/train_gate.js'), path.join(root, 'src/consensus/gates/rule_set_train.js')); fs.mkdirSync(path.join(root, 'src/activations')); - fs.renameSync(path.join(root, 'src/state_key_collation_activation.js'), - path.join(root, 'src/activations/state_key_collation_activation.js')); + fs.renameSync(path.join(root, 'src/consensus/gates/swq_source_cap_gate.js'), + path.join(root, 'src/activations/swq_source_cap_gate.js')); assert.strictEqual(readV2(root).hex, baseline.hex); }); }); @@ -145,7 +145,7 @@ describe('armed map v2: falsification on temp trees', function () { const root = tree(); edit(root, 'src/consensus/gate_registry/shared_rows_4.js', "addGate('swq_source_cap_activation.STAKE_WEIGHT_MAX_SOURCES', 'constant', 1000);\n", ''); - const failedBoot = boot(root, 'src/swq_source_cap_activation.js'); + const failedBoot = boot(root, 'src/consensus/gates/swq_source_cap_gate.js'); assert.notStrictEqual(failedBoot.status, 0, 'the shim booted with its registry row absent'); assert.ok(failedBoot.stderr.includes('swq_source_cap_activation.STAKE_WEIGHT_MAX_SOURCES'), failedBoot.stderr); const after = readV2(root); diff --git a/test/unit/consensus/armed_map/fingerprint_v2.test.js b/test/unit/consensus/armed_map/fingerprint.test.js similarity index 79% rename from test/unit/consensus/armed_map/fingerprint_v2.test.js rename to test/unit/consensus/armed_map/fingerprint.test.js index fdea0988..8825c443 100644 --- a/test/unit/consensus/armed_map/fingerprint_v2.test.js +++ b/test/unit/consensus/armed_map/fingerprint.test.js @@ -22,9 +22,10 @@ const path = require('path'); const { spawnSync } = require('child_process'); const ROOT = path.join(__dirname, '../../../..'); -const { computeArmedMapFingerprintV2 } = require(path.join(ROOT, 'src/consensus/armed_map/fingerprint_v2')); +const { computeArmedMapFingerprintV2 } = require(path.join(ROOT, 'src/consensus/armed_map/fingerprint')); const { ENTRIES, collectRows } = require(path.join(ROOT, 'src/consensus/armed_map/manifest')); const { canonicalValue, fingerprint } = require(path.join(ROOT, 'src/consensus/armed_map/canonical')); +const { get } = require(path.join(ROOT, 'src/consensus/gate_registry')); const { buildPin, compare } = require(path.join(ROOT, 'bin/pin-identity.js')); const logicPin = require(path.join(ROOT, 'bin/lib/carrier_logic_pin.js')); @@ -85,8 +86,10 @@ describe('armed map v2: fingerprint module and publication', function () { }); it('names each row by the sha256 of its exported value, so a mismatch points at the row', function () { - const { STATE_COMMITMENT_ACTIVATION } = require(path.join(ROOT, 'src/state_commitment_activation')); - const expected = crypto.createHash('sha256').update(canonicalValue(STATE_COMMITMENT_ACTIVATION), 'utf8').digest('hex'); + // The row read through the registry (the W4 caller contract), so the case does not + // name the gate module's path and survives its W5 move. + const row = get('state_commitment_activation.STATE_COMMITMENT_ACTIVATION'); + const expected = crypto.createHash('sha256').update(canonicalValue(row), 'utf8').digest('hex'); assert.strictEqual(computeArmedMapFingerprintV2().rows['state_commitment_activation.STATE_COMMITMENT_ACTIVATION'], expected); }); @@ -95,16 +98,16 @@ describe('armed map v2: fingerprint module and publication', function () { }); it('never lists a directory, so the value cannot depend on the file layout', function () { - for (const rel of ['canonical.js', 'manifest.js', 'fingerprint_v2.js']) { + for (const rel of ['canonical.js', 'manifest.js', 'fingerprint.js']) { const src = fs.readFileSync(path.join(ROOT, 'src/consensus/armed_map', rel), 'utf8'); assert.ok(!/readdirSync|readdir\(/.test(src), rel + ' reads a directory'); } }); - it('uses v2 for the legacy field and records version 2 plus the logic digest', function () { + it('uses v2 for the legacy field and records version 2 plus the logic digest, with no _v2 alias (W5)', function () { const pin = buildPin(); assert.strictEqual(pin.armed_map_fingerprint, computeArmedMapFingerprintV2().hex); - assert.strictEqual(pin.armed_map_fingerprint_v2, pin.armed_map_fingerprint); + assert.ok(!Object.prototype.hasOwnProperty.call(pin, 'armed_map_fingerprint_v2'), 'the W1 to W4 alias is gone at W5'); assert.strictEqual(pin.armed_map_fingerprint_version, 2); assert.strictEqual(pin.carrier_logic_digest, logicPin.digest(logicPin.readPin(ROOT))); }); @@ -112,7 +115,7 @@ describe('armed map v2: fingerprint module and publication', function () { describe('armed map v2: fingerprint module and publication', function () { - it('both /health bodies carry v2, version 2 and the carrier logic digest', function () { + it('both /health bodies carry v2, version 2 and the carrier logic digest, and no _v2 alias', function () { this.timeout(30000); const res = spawnSync(process.execPath, ['-e', HEALTH_DRIVE, require.resolve('proxyquire'), path.join(ROOT, 'src/api.js')], { cwd: ROOT, encoding: 'utf8', @@ -128,10 +131,11 @@ describe('armed map v2: fingerprint module and publication', function () { assert.strictEqual(healthy.status, 200); for (const reading of [starting, healthy]) { assert.strictEqual(reading.body.armed_map_fingerprint, hex); - assert.strictEqual(reading.body.armed_map_fingerprint_v2, hex); assert.strictEqual(reading.body.armed_map_fingerprint_version, 2); assert.strictEqual(reading.body.carrier_logic_digest, logicDigest); - assert.strictEqual(reading.keys.indexOf('armed_map_fingerprint_v2'), reading.keys.indexOf('armed_map_fingerprint') + 1); + // C4: the alias is gone; the version field directly follows the legacy field it describes. + assert.ok(!reading.keys.includes('armed_map_fingerprint_v2'), 'the _v2 alias must not be published'); + assert.strictEqual(reading.keys.indexOf('armed_map_fingerprint_version'), reading.keys.indexOf('armed_map_fingerprint') + 1); } }); @@ -139,7 +143,6 @@ describe('armed map v2: fingerprint module and publication', function () { it('records v2, its row hashes and count with no v1 fields', function () { const pin = buildPin(); assert.strictEqual(pin.armed_map_fingerprint, computeArmedMapFingerprintV2().hex); - assert.strictEqual(pin.armed_map_fingerprint_v2, computeArmedMapFingerprintV2().hex); assert.strictEqual(pin.armed_map_rows, ENTRIES.length); assert.deepStrictEqual(pin.armedMapRows, computeArmedMapFingerprintV2().rows); assert.ok(!Object.prototype.hasOwnProperty.call(pin, 'armedMapFingerprint')); @@ -149,12 +152,19 @@ describe('armed map v2: fingerprint module and publication', function () { it('reports a moved v2 and a changed row count, and nothing for an identical tree', function () { const fresh = buildPin(); assert.deepStrictEqual(compare(fresh, fresh), []); - const movedV2 = compare({ ...fresh, armed_map_fingerprint_v2: '0'.repeat(64) }, fresh); + const movedV2 = compare({ ...fresh, armed_map_fingerprint: '0'.repeat(64) }, fresh); assert.strictEqual(movedV2.length, 1); - assert.ok(movedV2[0].includes(fresh.armed_map_fingerprint_v2), movedV2[0]); + assert.ok(movedV2[0].includes(fresh.armed_map_fingerprint), movedV2[0]); assert.strictEqual(compare({ ...fresh, armed_map_rows: fresh.armed_map_rows - 1 }, fresh).length, 1); - assert.strictEqual(compare({ ...fresh, armed_map_fingerprint_v2: undefined }, fresh).length, 1, - 'a pin taken before v2 existed must not read as holding'); + // A pin from before v2 spells no version and holds v1 in the legacy field. + const preV2 = { ...fresh, armed_map_fingerprint: '1'.repeat(64), armed_map_fingerprint_version: undefined }; + assert.strictEqual(compare(preV2, fresh).length, 2, 'a pin taken before v2 existed must not read as holding'); + // A W3 or W4 pin still spells the _v2 alias this tool no longer writes: stale until re-pinned. + const aliased = compare({ ...fresh, armed_map_fingerprint_v2: fresh.armed_map_fingerprint }, fresh); + assert.strictEqual(aliased.length, 1, aliased.join('; ')); + assert.ok(aliased[0].includes('armed_map_fingerprint_v2'), 'the difference names the stale field: ' + aliased[0]); + assert.ok(!Object.prototype.hasOwnProperty.call(JSON.parse(fs.readFileSync(path.join(ROOT, 'bin/pins/identity.json'), 'utf8')), 'armed_map_fingerprint_v2'), + 'the committed pin must not carry the alias'); }); }); }); diff --git a/test/unit/consensus_primitive_conformance.test.js b/test/unit/consensus_primitive_conformance.test.js index 092d9a6c..8f523994 100644 --- a/test/unit/consensus_primitive_conformance.test.js +++ b/test/unit/consensus_primitive_conformance.test.js @@ -32,8 +32,8 @@ const assert = require('assert'); const fs = require('fs'); const path = require('path'); -const swq = require('../../src/stake_weighted_quorum.js'); -const equiv = require('../../src/equivocation_header.js'); +const swq = require('../../src/consensus/stake_weighted_quorum.js'); +const equiv = require('../../src/consensus/equivocation_header.js'); const LOCAL_DIR = path.join(__dirname, '../../src'); // Resolve the canonical xchain-documentation repo. Prefer an explicit path: GitHub CI @@ -108,13 +108,16 @@ describe('consensus-primitive conformance: canonical vectors @regression', funct describe('consensus-primitive conformance: byte-identity to canonical source @regression', function(){ before(function(){ if(!CANON_PRESENT){ if(process.env.XCHAIN_REQUIRE_SIBLINGS==='1') throw new Error('XCHAIN_REQUIRE_SIBLINGS=1 but canonical reference-impl dir not found at ' + CANON_DIR); this.skip(); } }); + // The two carriers sit under consensus/ on both sides since W5 (the same tail in + // every repo), so the compare is a raw byte compare of src/consensus/ against + // protocol/reference-impl/consensus/. ['stake_weighted_quorum.js', 'equivocation_header.js'].forEach(function(f){ it(f + ' is byte-identical to xchain-documentation/protocol/reference-impl', function(){ - const local = fs.readFileSync(path.join(LOCAL_DIR, f), 'utf8'); - const canon = fs.readFileSync(path.join(CANON_DIR, f), 'utf8'); + const local = fs.readFileSync(path.join(LOCAL_DIR, 'consensus', f), 'utf8'); + const canon = fs.readFileSync(path.join(CANON_DIR, 'consensus', f), 'utf8'); assert.strictEqual(local, canon, - 'this repo\'s ' + f + ' has drifted from the canonical source; ' + - 'edit xchain-documentation/protocol/reference-impl/' + f + ' and re-vendor all five copies.'); + 'this repo\'s consensus/' + f + ' has drifted from the canonical source; ' + + 'edit xchain-documentation/protocol/reference-impl/consensus/' + f + ' and re-vendor all five copies.'); }); }); }); diff --git a/test/unit/contractStateSubtree.test.js b/test/unit/contractStateSubtree.test.js index 2e04638f..d52caef9 100644 --- a/test/unit/contractStateSubtree.test.js +++ b/test/unit/contractStateSubtree.test.js @@ -58,7 +58,7 @@ const path = require('path'); const M = require('../../src/merkle.js'); const SC = require('../../src/state_commitment/index.js'); -const SUB = require('../../src/state_subtree_activation.js'); +const SUB = require('../../src/consensus/gates/state_subtree_gate.js'); const CST = require('../../src/contract_state_subtree.js'); const CHAIN = 'BTC', NETWORK = 'regtest'; diff --git a/test/unit/contractStateSubtree.test/contract_state_root_incremental_equals.test.js b/test/unit/contractStateSubtree.test/contract_state_root_incremental_equals.test.js index 8453f48a..f262d859 100644 --- a/test/unit/contractStateSubtree.test/contract_state_root_incremental_equals.test.js +++ b/test/unit/contractStateSubtree.test/contract_state_root_incremental_equals.test.js @@ -24,7 +24,7 @@ const assert = require('assert'); -const SUB = require('../../../src/state_subtree_activation.js'); +const SUB = require('../../../src/consensus/gates/state_subtree_gate.js'); const CST = require('../../../src/contract_state_subtree.js'); const { FakeDb, CHAIN, NETWORK } = require('./helpers/fake_db'); diff --git a/test/unit/contractStateSubtree.test/contract_state_root_shadow_derivation.test.js b/test/unit/contractStateSubtree.test/contract_state_root_shadow_derivation.test.js index 3994041b..d7a7292d 100644 --- a/test/unit/contractStateSubtree.test/contract_state_root_shadow_derivation.test.js +++ b/test/unit/contractStateSubtree.test/contract_state_root_shadow_derivation.test.js @@ -28,7 +28,7 @@ const assert = require('assert'); const SC = require('../../../src/state_commitment/index.js'); -const SUB = require('../../../src/state_subtree_activation.js'); +const SUB = require('../../../src/consensus/gates/state_subtree_gate.js'); const CST = require('../../../src/contract_state_subtree.js'); const { FakeDb, EMPTY, CHAIN, NETWORK } = require('./helpers/fake_db'); diff --git a/test/unit/contractStateSubtree.test/contract_state_root_strict_read_faults.test.js b/test/unit/contractStateSubtree.test/contract_state_root_strict_read_faults.test.js index 001eaedf..2dec6cef 100644 --- a/test/unit/contractStateSubtree.test/contract_state_root_strict_read_faults.test.js +++ b/test/unit/contractStateSubtree.test/contract_state_root_strict_read_faults.test.js @@ -27,7 +27,7 @@ const assert = require('assert'); const SC = require('../../../src/state_commitment/index.js'); -const SUB = require('../../../src/state_subtree_activation.js'); +const SUB = require('../../../src/consensus/gates/state_subtree_gate.js'); const { FakeDb, armedAt, CHAIN, NETWORK } = require('./helpers/fake_db'); diff --git a/test/unit/contractStateSubtree.test/contract_state_root_strict_reads.test.js b/test/unit/contractStateSubtree.test/contract_state_root_strict_reads.test.js index 24399e40..2a259426 100644 --- a/test/unit/contractStateSubtree.test/contract_state_root_strict_reads.test.js +++ b/test/unit/contractStateSubtree.test/contract_state_root_strict_reads.test.js @@ -24,7 +24,7 @@ const assert = require('assert'); const SC = require('../../../src/state_commitment/index.js'); -const SUB = require('../../../src/state_subtree_activation.js'); +const SUB = require('../../../src/consensus/gates/state_subtree_gate.js'); const { FakeDb, EMPTY, armedAt, CHAIN, NETWORK } = require('./helpers/fake_db'); diff --git a/test/unit/contractStateSubtree.test/helpers/block_row.js b/test/unit/contractStateSubtree.test/helpers/block_row.js index 490eac47..3ab5c945 100644 --- a/test/unit/contractStateSubtree.test/helpers/block_row.js +++ b/test/unit/contractStateSubtree.test/helpers/block_row.js @@ -22,7 +22,7 @@ const M = require('../../../../src/merkle.js'); const SC = require('../../../../src/state_commitment/index.js'); -const SUB = require('../../../../src/state_subtree_activation.js'); +const SUB = require('../../../../src/consensus/gates/state_subtree_gate.js'); const { CHAIN, NETWORK } = require('./fake_db'); diff --git a/test/unit/contractStateSubtree.test/helpers/fake_db.js b/test/unit/contractStateSubtree.test/helpers/fake_db.js index 7de4e6cd..548bc942 100644 --- a/test/unit/contractStateSubtree.test/helpers/fake_db.js +++ b/test/unit/contractStateSubtree.test/helpers/fake_db.js @@ -33,7 +33,7 @@ 'use strict'; const SC = require('../../../../src/state_commitment/index.js'); -const SUB = require('../../../../src/state_subtree_activation.js'); +const SUB = require('../../../../src/consensus/gates/state_subtree_gate.js'); const CST = require('../../../../src/contract_state_subtree.js'); const CHAIN = 'BTC', NETWORK = 'regtest'; diff --git a/test/unit/contractStateSubtree.test/helpers/shadow_window.js b/test/unit/contractStateSubtree.test/helpers/shadow_window.js index c5048391..5ebaf2e3 100644 --- a/test/unit/contractStateSubtree.test/helpers/shadow_window.js +++ b/test/unit/contractStateSubtree.test/helpers/shadow_window.js @@ -21,7 +21,7 @@ */ 'use strict'; -const SUB = require('../../../../src/state_subtree_activation.js'); +const SUB = require('../../../../src/consensus/gates/state_subtree_gate.js'); const { CHAIN, NETWORK } = require('./fake_db'); diff --git a/test/unit/db_stake_weight_collation.test.js b/test/unit/db_stake_weight_collation.test.js index 19f170e1..f96d9177 100644 --- a/test/unit/db_stake_weight_collation.test.js +++ b/test/unit/db_stake_weight_collation.test.js @@ -26,7 +26,7 @@ const assert = require('assert'); const sinon = require('sinon'); const Database = require('../../src/db'); -const swc = require('../../src/stake_weight_collation_activation'); +const swc = require('../../src/consensus/gates/stake_weight_collation_gate'); function makeUtil() { return { isNull: (x) => x == null, logError: () => {}, throwError: () => {} }; } diff --git a/test/unit/db_swq_source_cap.test.js b/test/unit/db_swq_source_cap.test.js index 5b64fade..023443f3 100644 --- a/test/unit/db_swq_source_cap.test.js +++ b/test/unit/db_swq_source_cap.test.js @@ -26,8 +26,8 @@ const assert = require('assert'); const sinon = require('sinon'); const Database = require('../../src/db'); -const swqCap = require('../../src/swq_source_cap_activation'); -const swc = require('../../src/stake_weight_collation_activation'); +const swqCap = require('../../src/consensus/gates/swq_source_cap_gate'); +const swc = require('../../src/consensus/gates/stake_weight_collation_gate'); const MAX_SOURCES = swqCap.STAKE_WEIGHT_MAX_SOURCES; const MAX_KEYS = swqCap.STAKE_WEIGHT_MAX_KEYS_PER_SOURCE; diff --git a/test/unit/escrowLeafSubtree.test.js b/test/unit/escrowLeafSubtree.test.js index 77a8ffd5..4683b52b 100644 --- a/test/unit/escrowLeafSubtree.test.js +++ b/test/unit/escrowLeafSubtree.test.js @@ -43,7 +43,7 @@ const assert = require('assert'); const { siblingCheckout, skipOrFail } = require('../helpers/sibling_checkout.js'); const M = require('../../src/merkle.js'); const SC = require('../../src/state_commitment/index.js'); -const SUB = require('../../src/state_subtree_activation.js'); +const SUB = require('../../src/consensus/gates/state_subtree_gate.js'); const ESC = require('../../src/escrow_leaf_subtree.js'); const CHAIN = 'BTC', NETWORK = 'regtest'; diff --git a/test/unit/escrowLeafSubtree.test/xchain_esc_locked_leaf_the.test.js b/test/unit/escrowLeafSubtree.test/xchain_esc_locked_leaf_the.test.js index ff99507e..225c851b 100644 --- a/test/unit/escrowLeafSubtree.test/xchain_esc_locked_leaf_the.test.js +++ b/test/unit/escrowLeafSubtree.test/xchain_esc_locked_leaf_the.test.js @@ -25,7 +25,7 @@ const assert = require('assert'); const M = require('../../../src/merkle.js'); const SC = require('../../../src/state_commitment/index.js'); -const SUB = require('../../../src/state_subtree_activation.js'); +const SUB = require('../../../src/consensus/gates/state_subtree_gate.js'); const ESC = require('../../../src/escrow_leaf_subtree.js'); const { FakeDb, CHAIN, NETWORK, ADDR, TICK } = require('./helpers/fake_db'); diff --git a/test/unit/health/carrier_logic.test.js b/test/unit/health/carrier_logic.test.js index 38af588a..36eb4c2e 100644 --- a/test/unit/health/carrier_logic.test.js +++ b/test/unit/health/carrier_logic.test.js @@ -27,7 +27,7 @@ const ROOT = path.join(__dirname, '../../..'); const MODULE = path.join(ROOT, 'src/health/carrier_logic.js'); const health = require(MODULE); const logicPin = require(path.join(ROOT, 'bin/lib/carrier_logic_pin.js')); -const { computeArmedMapFingerprintV2 } = require(path.join(ROOT, 'src/consensus/armed_map/fingerprint_v2')); +const { computeArmedMapFingerprintV2 } = require(path.join(ROOT, 'src/consensus/armed_map/fingerprint')); const HEX64 = /^[0-9a-f]{64}$/; @@ -45,7 +45,7 @@ function freshCopy(withPin) { } // Boots startApi() with the service, the coin-pin check and the listener -// stubbed (the shape armed_map/fingerprint_v2.test.js uses) and prints the +// stubbed (the shape armed_map/fingerprint.test.js uses) and prints the // 503 body, which is the consensusIdentityFields() spread the route serves. const HEALTH_DRIVE = ` const http = require('http'); @@ -107,7 +107,7 @@ describe('health/carrier_logic: the published carrier logic digest', function () assert.ok(!/require\(['"]\.\.\/bin/.test(api), 'src/api.js requires under bin/'); }); - it('/health carries the digest as its own field beside v2, version 2, v2 equal to the legacy field', function () { + it('/health carries the digest as its own field beside v2 and version 2, with no _v2 alias', function () { this.timeout(30000); const res = spawnSync(process.execPath, ['-e', HEALTH_DRIVE, require.resolve('proxyquire'), path.join(ROOT, 'src/api.js')], { cwd: ROOT, encoding: 'utf8', @@ -120,7 +120,7 @@ describe('health/carrier_logic: the published carrier logic digest', function () assert.strictEqual(body.carrier_logic_digest, logicPin.digest(logicPin.readPin(ROOT))); assert.match(body.carrier_logic_digest, HEX64); assert.strictEqual(body.armed_map_fingerprint_version, 2); - assert.strictEqual(body.armed_map_fingerprint_v2, computeArmedMapFingerprintV2().hex); - assert.strictEqual(body.armed_map_fingerprint, body.armed_map_fingerprint_v2); + assert.strictEqual(body.armed_map_fingerprint, computeArmedMapFingerprintV2().hex); + assert.ok(!Object.prototype.hasOwnProperty.call(body, 'armed_map_fingerprint_v2'), 'the W1 to W4 alias is gone at W5'); }); }); diff --git a/test/unit/repo_guards/carrier_logic_pin.test.js b/test/unit/repo_guards/carrier_logic_pin.test.js index aa1155dd..cbcfd93b 100644 --- a/test/unit/repo_guards/carrier_logic_pin.test.js +++ b/test/unit/repo_guards/carrier_logic_pin.test.js @@ -174,15 +174,61 @@ describe('bin/lib/carrier_logic_pin.js: --retire and --move', () => { assert.strictEqual(pinModule.digest(repo.pin), pinModule.digest(pinModule.readPin(repo.dir)), 'a move leaves the digest alone'); }); - it('(j) --move is refused when the new path carries different logic, and the pin is untouched', () => { - fs.writeFileSync(path.join(repo.dir, 'src', 'deep', 'thing_gate.js'), repo.source.replace("activeAt('k', h)", "!activeAt('k', h)")); - assert.throws(() => pinModule.moveEntry(repo.dir, repo.pin, 'thing_activation', 'src/deep/thing_gate.js', 'row 18'), - (e) => e.exitCode === 1 && /not the pinned logic/.test(e.message)); + it('(j) --move refuses a missing destination and leaves the pin untouched', () => { assert.throws(() => pinModule.moveEntry(repo.dir, repo.pin, 'thing_activation', 'src/deep/missing_gate.js', 'row 18'), /does not exist/); assert.deepStrictEqual(repo.pin, pinModule.readPin(repo.dir), 'a refused move writes nothing'); }); }); +describe('bin/lib/carrier_logic_pin.js: a move that changes logic', () => { + let repo; + beforeEach(() => { repo = scratchRepo(); }); + afterEach(() => { fs.rmSync(repo.dir, { recursive: true, force: true }); }); + + it('(o) --move refuses changed logic without a reason and changes no pin bytes', () => { + const before = JSON.stringify(repo.pin); + const history = JSON.stringify(repo.pin.repins); + const moved = repo.source.replace("activeAt('k', h)", "!activeAt('k', h)"); + fs.writeFileSync(path.join(repo.dir, 'src', 'deep', 'thing_gate.js'), moved); + assert.throws(() => pinModule.moveEntry(repo.dir, repo.pin, 'thing_activation', 'src/deep/thing_gate.js'), + (e) => e.exitCode === 1 && /requires --reason/.test(e.message)); + assert.strictEqual(JSON.stringify(repo.pin), before); + assert.strictEqual(JSON.stringify(repo.pin.repins), history); + }); + + it('(p) --move records a changed hash and path together when given a reason', () => { + const entry = repo.pin.entries.thing_activation; + Object.assign(entry, { twins: ['xchain-sync'], note: 'keep this note' }); + const committed = JSON.parse(JSON.stringify(repo.pin)); + const moved = repo.source.replace("activeAt('k', h)", "!activeAt('k', h)"); + const movedHash = pinModule.tokenHash(moved); + fs.writeFileSync(path.join(repo.dir, 'src', 'deep', 'thing_gate.js'), moved); + pinModule.moveEntry(repo.dir, repo.pin, 'thing_activation', 'src/deep/thing_gate.js', 'combined move'); + assert.deepStrictEqual(repo.pin.entries.thing_activation, { + path: 'src/deep/thing_gate.js', hash: movedHash, twins: ['xchain-sync'], note: 'keep this note', + }); + assert.strictEqual(repo.pin.repins.length, 1); + const record = repo.pin.repins[0]; + assert.deepStrictEqual(record, { + id: 'thing_activation', from: repo.hash, to: movedHash, + path: { from: 'src/thing_activation.js', to: 'src/deep/thing_gate.js' }, + date: record.date, reason: 'combined move', + }); + assert.match(record.date, /^\d{4}-\d{2}-\d{2}$/); + assert.deepStrictEqual(pinModule.unrecordedChanges(committed, repo.pin), []); + delete record.path; + assert.deepStrictEqual(pinModule.unrecordedChanges(committed, repo.pin), [ + 'thing_activation: hash and path changed with no combined --move record', + ]); + repo.pin.repins.push({ + id: 'thing_activation', from: repo.hash, to: repo.hash, + path: { from: 'src/thing_activation.js', to: 'src/deep/thing_gate.js' }, + }); + assert.strictEqual(pinModule.unrecordedChanges(committed, repo.pin).length, 1, + 'separate hash-only and path-only records do not prove the combined change'); + }); +}); + describe('bin/lib/carrier_logic_pin.js: the records rule (b) accepts and refuses', () => { const h1 = 'a'.repeat(64); const h2 = 'b'.repeat(64); diff --git a/test/unit/rollback_coverage.test.js b/test/unit/rollback_coverage.test.js index 06b6b861..a483b07e 100644 --- a/test/unit/rollback_coverage.test.js +++ b/test/unit/rollback_coverage.test.js @@ -100,7 +100,7 @@ const lifecycleTwin = require('../../src/table_lifecycle'); const pathMod = require('path'); const fs = require('fs'); const assertLocal = require('assert'); -const sh = require('../../src/stateHash'); +const sh = require('../../src/consensus/state_hash'); const widenSet = require('../../src/schema/utf8mb4_columns'); const { RECOMPUTED, SPECIAL_CASE, ROLLBACK_EXEMPT, INDEXER_LOCAL } = lifecycleTwin.replicaRollbackBuckets(); @@ -843,9 +843,9 @@ describe('Rollback coverage guard @regression', function(){ // The publisher-scope flag day is one file, twinned. A per-network height that differs // between source and replica is a fleet split at the reorg the gate governs. - it('archive_rollback_author_scope_activation.js is byte-identical across xchain-indexer and xchain-sync', function(){ + it('archive_rollback_author_scope_gate.js is byte-identical across xchain-indexer and xchain-sync', function(){ const fs = require('fs'), pathMod = require('path'); - const rel = 'src/archive_rollback_author_scope_activation.js'; + const rel = 'src/consensus/gates/archive_rollback_author_scope_gate.js'; const indexerPath = indexerFile(rel); if(!requireSibling(this, indexerPath)) return; const syncPath = pathMod.resolve(__dirname, '../..', rel); @@ -859,7 +859,7 @@ describe('Rollback coverage guard @regression', function(){ // runs the legacy unscoped reset on a fleet whose source indexer runs the scoped one. // ClientRollback must refuse to construct at all rather than resolve to that fallback. it('demands a known network, because the publisher scope is armed', function(){ - const { ARCHIVE_ROLLBACK_AUTHOR_SCOPE_ACTIVATION } = require('../../src/archive_rollback_author_scope_activation'); + const { ARCHIVE_ROLLBACK_AUTHOR_SCOPE_ACTIVATION } = require('../../src/consensus/gates/archive_rollback_author_scope_gate'); const INERT = 9999999999; const armed = Object.keys(ARCHIVE_ROLLBACK_AUTHOR_SCOPE_ACTIVATION) .filter(n => ARCHIVE_ROLLBACK_AUTHOR_SCOPE_ACTIVATION[n] !== INERT); @@ -884,7 +884,7 @@ describe('Rollback coverage guard @regression', function(){ // put the whole fleet back on the unscoped reset) fails here rather than in production. it('publisher-scope heights are the 2026-09-09 ruling values', function(){ const { ARCHIVE_ROLLBACK_AUTHOR_SCOPE_ACTIVATION, isArchiveRollbackAuthorScopeActive } = - require('../../src/archive_rollback_author_scope_activation'); + require('../../src/consensus/gates/archive_rollback_author_scope_gate'); assert.deepStrictEqual(ARCHIVE_ROLLBACK_AUTHOR_SCOPE_ACTIVATION, { mainnet: 0, testnet: 67915000, regtest: 9999999999 }); // Mainnet is scoped from genesis; testnet only at its flag day; regtest stays off. @@ -919,9 +919,9 @@ describe('Rollback coverage guard @regression', function(){ 'ARCHIVE_CHUNK_HEIGHT_COL must be c.block_index_doge (block_index is NULL on v2 chunks)'); assertLocal.ok(!/AND c\.block_index BETWEEN/.test(ur), 'updatedRows.js must not regress to the never-populated c.block_index key'); - // Twin-parity: the indexer stateHash.js copy (when the sibling checkout exists) + // Twin-parity: the indexer state_hash.js copy (when the sibling checkout exists) // must carry the identical constant, or the two repos disagree on the parent set. - const indexerPath = indexerFile('src/stateHash.js'); + const indexerPath = indexerFile('src/consensus/state_hash.js'); if(fs.existsSync(indexerPath)){ const ish = require(indexerPath); assertLocal.deepStrictEqual(ish.ARCHIVE_HEAD_VERSIONS, sh.ARCHIVE_HEAD_VERSIONS, @@ -1017,8 +1017,8 @@ describe('Rollback coverage guard @regression', function(){ // false-halt generator. Lock them identical (skip if the sibling indexer repo absent). it('stateHash.js is byte-identical across xchain-sync and xchain-indexer (cross-repo twin)', function(){ const fs = require('fs'), pathMod = require('path'); - const syncPath = pathMod.resolve(__dirname, '../../src/stateHash.js'); - const indexerPath = indexerFile('src/stateHash.js'); + const syncPath = pathMod.resolve(__dirname, '../../src/consensus/state_hash.js'); + const indexerPath = indexerFile('src/consensus/state_hash.js'); if(!requireSibling(this, indexerPath)) return; assert.strictEqual(fs.readFileSync(syncPath, 'utf8'), fs.readFileSync(indexerPath, 'utf8'), 'stateHash.js drifted between xchain-sync and xchain-indexer; keep the twin byte-identical'); @@ -1053,10 +1053,10 @@ describe('Rollback coverage guard @regression', function(){ // GENERATES the replicated topology and both rollback table sets; a drifted copy // would silently re-open the very source<->replica divergence it exists to close. // Lock them byte-identical (skip if the sibling repo absent). - // state_key_collation_activation.js gates the state_key COLLATE in the - // contract_hash/block_merkle_root preimage on BOTH sides; a drifted copy - // forks the recomputed hashes at/after an armed height. - // state_subtree_activation.js is the flag-day gate for the RESERVED state_root + // The state_key_collation_activation registry row gates the state_key COLLATE + // in the contract_hash/block_merkle_root preimage on BOTH sides through the + // shared registry parts, which have their own twin guard. + // state_subtree_gate.js is the flag-day gate for the RESERVED state_root // slots (ownership/tokens/contract_state) and for the balances_root escrow leaf. // It is inert today, but it decides on BOTH sides which sub-roots stop being // EMPTY at an armed height; a drifted copy forks state_root the moment a slot @@ -1079,17 +1079,17 @@ describe('Rollback coverage guard @regression', function(){ // copy means an origin that accepts a 4-byte character and a replica that halts on it // with errno 1366 - a fleet-wide follower halt with no schema error upstream. // The two sides no longer share one relative path. xchain-sync keeps its twins flat - // under src/ except the utf8mb4 map, which sits in src/schema/, while the indexer has - // sorted its copies into feature directories, so the indexer tail is spelled out per + // under src/ except the utf8mb4 map, which sits in src/schema/, and the W5 gates, + // which sit under src/consensus/gates/ on both sides, while the indexer has sorted + // its other copies into feature directories, so the indexer tail is spelled out per // twin and a third element names the sync path where it is not src/ plus the basename. // The pairs below compare exactly the same code the single-tail loop did. for(const [twin, indexerRel, syncRel] of [ ['merkle.js', 'src/consensus/merkle.js'], - ['state_commitment_activation.js', 'src/state_commitment_activation.js'], - ['swq_source_cap_activation.js', 'src/swq_source_cap_activation.js'], - ['state_key_collation_activation.js', 'src/state_key_collation_activation.js'], - ['stake_weight_collation_activation.js', 'src/stake_weight_collation_activation.js'], - ['state_subtree_activation.js', 'src/state_subtree_activation.js'], + ['state_commitment_gate.js', 'src/consensus/gates/state_commitment_gate.js', 'consensus/gates/state_commitment_gate.js'], + ['swq_source_cap_gate.js', 'src/consensus/gates/swq_source_cap_gate.js', 'consensus/gates/swq_source_cap_gate.js'], + ['stake_weight_collation_gate.js', 'src/consensus/gates/stake_weight_collation_gate.js', 'consensus/gates/stake_weight_collation_gate.js'], + ['state_subtree_gate.js', 'src/consensus/gates/state_subtree_gate.js', 'consensus/gates/state_subtree_gate.js'], ['contract_state_subtree.js', 'src/consensus/contract_state_subtree.js'], ['escrow_leaf_subtree.js', 'src/consensus/escrow_leaf_subtree.js'], ['db/subtree/node_store_rows.js', 'src/db/subtree/node_store_rows.js'], @@ -1136,17 +1136,17 @@ describe('Rollback coverage guard @regression', function(){ // is inert (identical state_root to the two-sub-root v1 assembly) and that the // slot list matches merkle.STATE_SUBTREES. Both repos must assert the same // thing, or one side can land an arming change the other never checked. - // state_subtree_activation.js has a THIRD carrier: xchain-sdk ships it as a + // state_subtree_gate.js has a THIRD carrier: xchain-sdk ships it as a // client-facing consensus constant, because no proof can tell a client whether // a slot is live (an armed-but-empty slot and an inert slot commit the same // EMPTY_SMT_ROOT). The loop above only pairs sync with the indexer, so the SDK // copy is checked here as well; xchain-sdk carries its own copy of this guard // plus a golden pin for standalone checkouts. - it('state_subtree_activation.js is byte-identical in xchain-sdk too (client liveness export)', function(){ + it('state_subtree_gate.js is byte-identical in xchain-sdk too (client liveness export)', function(){ const fs = require('fs'), pathMod = require('path'); - const sdkPath = pathMod.resolve(__dirname, '..', '..', '..', 'xchain-sdk/src/state_subtree_activation.js'); + const sdkPath = pathMod.resolve(__dirname, '..', '..', '..', 'xchain-sdk/src/consensus/gates/state_subtree_gate.js'); if(!requireSibling(this, sdkPath)) return; - assert.strictEqual(fs.readFileSync(pathMod.resolve(__dirname, '../../src/state_subtree_activation.js'), 'utf8'), + assert.strictEqual(fs.readFileSync(pathMod.resolve(__dirname, '../../src/consensus/gates/state_subtree_gate.js'), 'utf8'), fs.readFileSync(sdkPath, 'utf8'), 'the SDK activation copy drifted; a client would read different armed heights than the fleet commits'); }); @@ -1159,11 +1159,11 @@ describe('Rollback coverage guard @regression', function(){ // either serves meaningless absence proofs early (the ยง4 hazard the refusal // exists for; the SDK verifier's own copy still protects conforming clients) // or refuses real proofs late (an availability gap). - it('state_subtree_activation.js is byte-identical in xchain-explorer too (escrow-leaf liveness refusal)', function(){ + it('state_subtree_gate.js is byte-identical in xchain-explorer too (escrow-leaf liveness refusal)', function(){ const fs = require('fs'), pathMod = require('path'); - const expPath = pathMod.resolve(__dirname, '..', '..', '..', 'xchain-explorer/src/state_subtree_activation.js'); + const expPath = pathMod.resolve(__dirname, '..', '..', '..', 'xchain-explorer/src/consensus/gates/state_subtree_gate.js'); if(!requireSibling(this, expPath)) return; - assert.strictEqual(fs.readFileSync(pathMod.resolve(__dirname, '../../src/state_subtree_activation.js'), 'utf8'), + assert.strictEqual(fs.readFileSync(pathMod.resolve(__dirname, '../../src/consensus/gates/state_subtree_gate.js'), 'utf8'), fs.readFileSync(expPath, 'utf8'), 'the explorer activation copy drifted; its escrow-leaf proof refusal boundary would disagree with the fleet'); }); @@ -1200,9 +1200,9 @@ describe('Rollback coverage guard @regression', function(){ // The state_hash selection must mirror the SAME mutation classes the updated_rows + // cooldownCredits channels carry (and that ClientRollback reverses), keyed on the same // block columns, or the integrity hash covers a different row set than it protects. - it('stateHash.js selection predicates mirror the replicated mutation classes', function(){ + it('state_hash.js selection predicates mirror the replicated mutation classes', function(){ const fs = require('fs'), pathMod = require('path'); - const src = fs.readFileSync(pathMod.resolve(__dirname, '../../src/stateHash.js'), 'utf8') + const src = fs.readFileSync(pathMod.resolve(__dirname, '../../src/consensus/state_hash.js'), 'utf8') .replace(/[`"']/g, ' ').replace(/\s+\+\s+/g, ' ').replace(/\s+/g, ' '); const PREDICATES = [ { name: 'deactivation_block stamp', re: /WHERE deactivation_block BETWEEN \? AND \?/ }, @@ -1219,7 +1219,7 @@ describe('Rollback coverage guard @regression', function(){ { name: 'token supply refresh', re: /SELECT tk\.tick AS tick, t\.supply AS supply FROM tokens t/ }, ]; for(const p of PREDICATES){ - assert.ok(p.re.test(src), `stateHash.js is missing the ${p.name} selection; its hash would not cover that replicated mutation class`); + assert.ok(p.re.test(src), `state_hash.js is missing the ${p.name} selection; its hash would not cover that replicated mutation class`); } // The mid-chain-armed classes (poll_finalize / token_supply) are gated by // per-chain ':' keys, so the follower's recompute MUST @@ -1306,7 +1306,7 @@ describe('Rollback coverage guard @regression', function(){ }); it('F-2: buildStateHashData includes the anchor CRC-failure parent in the anchor_invalid preimage class (value fixture)', async function(){ - const { buildStateHashData } = require('../../src/stateHash'); + const { buildStateHashData } = require('../../src/consensus/state_hash'); let anchor = { action_index: 301, status: 'invalid_archive' }; let db = { doQuery: async (sql) => { @@ -1325,7 +1325,7 @@ describe('Rollback coverage guard @regression', function(){ }); it('F-2: buildStateHashData includes cooldown-maturity refund credit in credits class (maturity fixture)', async function(){ - const { buildStateHashData } = require('../../src/stateHash'); + const { buildStateHashData } = require('../../src/consensus/state_hash'); let credit = { action_index: 77, address: 'bc1qtest', tick: 'GAS', amount: '1000' }; let db = { doQuery: async (sql) => { diff --git a/test/unit/sibling_coverage.test.js b/test/unit/sibling_coverage.test.js index 182a5ad9..fb3890c4 100644 --- a/test/unit/sibling_coverage.test.js +++ b/test/unit/sibling_coverage.test.js @@ -72,11 +72,11 @@ const SIBLINGS = [ altEnvs: ['XCHAIN_DECODER_SQL_PATH'], guards: 'the generated-column parity and the decoder table-classification exhaustiveness against the decoder schema' }, { repo: 'xchain-sdk', envs: [], - marker: path.join('src', 'state_subtree_activation.js'), - guards: 'state_subtree_activation.js byte-identity in its client-liveness carrier' }, + marker: path.join('src', 'consensus', 'gates', 'state_subtree_gate.js'), + guards: 'state_subtree_gate.js byte-identity in its client-liveness carrier' }, { repo: 'xchain-explorer', envs: [], - marker: path.join('src', 'state_subtree_activation.js'), - guards: 'state_subtree_activation.js byte-identity in its escrow-leaf refusal carrier' }, + marker: path.join('src', 'consensus', 'gates', 'state_subtree_gate.js'), + guards: 'state_subtree_gate.js byte-identity in its escrow-leaf refusal carrier' }, ]; function resolve(entry) { diff --git a/test/unit/stateSubtreeActivation.test.js b/test/unit/stateSubtreeActivation.test.js index 31e14ae8..3084c2cb 100644 --- a/test/unit/stateSubtreeActivation.test.js +++ b/test/unit/stateSubtreeActivation.test.js @@ -41,7 +41,7 @@ const assert = require('assert'); const M = require('../../src/merkle.js'); const SC = require('../../src/state_commitment/index.js'); -const SUB = require('../../src/state_subtree_activation.js'); +const SUB = require('../../src/consensus/gates/state_subtree_gate.js'); // Snapshot of the REAL armed heights, taken before any test mutates the map, so // a scratch-arm can restore rather than delete (deleting disarms the chain for @@ -218,9 +218,9 @@ describe('state_root reserved sub-trees: gate is inert EXCEPT the armed set @reg // collation-FOLDED key set and forks against a binary-collation reader. All // three testnets are genesis-active there, so 0 is the lowest legal height // and this is the assertion that fails if either map moves off genesis alone. - const COLLATION = require('../../src/state_key_collation_activation.js'); + const gateRegistry = require('../../src/consensus/gate_registry'); for(const coin of ['BTC', 'LTC', 'DOGE']) - assert.ok(COLLATION.isStateKeyBinCollationActive(0, 'testnet', coin), + assert.ok(gateRegistry.activeAt('state_key_collation_activation.STATE_KEY_COLLATION_ACTIVATION', 'testnet', coin, 0, null), coin + ':testnet Stage A arms at 0, so its collation must be genesis-active too'); // Genesis on testnet must not have leaked onto the other two networks: the // maps are read by an exact ':' key, and a genesis height is diff --git a/test/unit/stateSubtreeActivation.test/state_root_reserved_sub_trees.test.js b/test/unit/stateSubtreeActivation.test/state_root_reserved_sub_trees.test.js index e43e57f9..cf307980 100644 --- a/test/unit/stateSubtreeActivation.test/state_root_reserved_sub_trees.test.js +++ b/test/unit/stateSubtreeActivation.test/state_root_reserved_sub_trees.test.js @@ -25,7 +25,7 @@ const assert = require('assert'); const M = require('../../../src/merkle.js'); const SC = require('../../../src/state_commitment/index.js'); -const SUB = require('../../../src/state_subtree_activation.js'); +const SUB = require('../../../src/consensus/gates/state_subtree_gate.js'); // Snapshot of the REAL armed heights, taken before any test mutates the map, so // a scratch-arm can restore rather than delete (deleting disarms the chain for @@ -105,7 +105,7 @@ describe('state_root reserved sub-trees: gate is inert EXCEPT the armed set @reg it('no environment variable can arm a slot', function(){ // An env-tunable consensus height is a fork switch on an operator's shell. // Nothing in the module may read process.env at all. - const src = require('fs').readFileSync(require('path').resolve(__dirname, '../../../src/state_subtree_activation.js'), 'utf8'); + const src = require('fs').readFileSync(require('path').resolve(__dirname, '../../../src/consensus/gates/state_subtree_gate.js'), 'utf8'); assert.ok(!/process\.env/.test(src), 'state_subtree_activation.js must not read process.env'); }); }); diff --git a/test/unit/stateSubtreeActivation.test/state_root_reserved_sub_trees_2.test.js b/test/unit/stateSubtreeActivation.test/state_root_reserved_sub_trees_2.test.js index 6b471ef8..60067e5d 100644 --- a/test/unit/stateSubtreeActivation.test/state_root_reserved_sub_trees_2.test.js +++ b/test/unit/stateSubtreeActivation.test/state_root_reserved_sub_trees_2.test.js @@ -26,7 +26,7 @@ const assert = require('assert'); const M = require('../../../src/merkle.js'); const SC = require('../../../src/state_commitment/index.js'); -const SUB = require('../../../src/state_subtree_activation.js'); +const SUB = require('../../../src/consensus/gates/state_subtree_gate.js'); // Snapshot of the REAL armed heights, taken before any test mutates the map, so // a scratch-arm can restore rather than delete (deleting disarms the chain for diff --git a/test/unit/stateSubtreeActivation.test/state_root_reserved_sub_trees_armed_set.test.js b/test/unit/stateSubtreeActivation.test/state_root_reserved_sub_trees_armed_set.test.js index d37a9197..43eb25c6 100644 --- a/test/unit/stateSubtreeActivation.test/state_root_reserved_sub_trees_armed_set.test.js +++ b/test/unit/stateSubtreeActivation.test/state_root_reserved_sub_trees_armed_set.test.js @@ -27,7 +27,7 @@ 'use strict'; const assert = require('assert'); -const SUB = require('../../../src/state_subtree_activation.js'); +const SUB = require('../../../src/consensus/gates/state_subtree_gate.js'); describe('state_root reserved sub-trees: gate is inert EXCEPT the armed set @regression', function(){ diff --git a/test/unit/state_commitment.test.js b/test/unit/state_commitment.test.js index aadfce5a..4dc09400 100644 --- a/test/unit/state_commitment.test.js +++ b/test/unit/state_commitment.test.js @@ -25,7 +25,7 @@ const assert = require('assert'); const M = require('../../src/merkle.js'); const SC = require('../../src/state_commitment/index.js'); -const act = require('../../src/state_commitment_activation.js'); +const act = require('../../src/consensus/gates/state_commitment_gate.js'); // Deterministic pseudo-random key + amount derived from an index. function keyFor(i){ return M.sha256(Buffer.from('key:' + i, 'utf8')); } // 32-byte key buf diff --git a/test/unit/state_hash.test.js b/test/unit/state_hash.test.js index 3f7d22c3..92914105 100644 --- a/test/unit/state_hash.test.js +++ b/test/unit/state_hash.test.js @@ -21,7 +21,7 @@ ********************************************************************/ const assert = require('assert'); -const { buildStateHashData, STATE_HASH_VERSION } = require('../../src/stateHash'); +const { buildStateHashData, STATE_HASH_VERSION } = require('../../src/consensus/state_hash'); const Utility = require('../../src/util'); const vectors = require('../fixtures/state-hash-vectors.json'); diff --git a/test/unit/state_hash_index_map.test.js b/test/unit/state_hash_index_map.test.js index e664090d..cc3a4373 100644 --- a/test/unit/state_hash_index_map.test.js +++ b/test/unit/state_hash_index_map.test.js @@ -27,7 +27,7 @@ const { buildStateHashData, isIndexMapStateHashActive, INDEX_MAP_STATE_HASH_ACTIVATION, POLL_FINALIZE_STATE_HASH_ACTIVATION, TOKEN_SUPPLY_STATE_HASH_ACTIVATION, BET_STATUS_STATE_HASH_ACTIVATION, -} = require('../../src/stateHash'); +} = require('../../src/consensus/state_hash'); const util = new Utility(); const PREFEATURE_KEYS = ['deactivations', 'slashes', 'request_status', 'cooldown', 'credits', 'anchor_invalid', 'block_index', 'state_hash_version']; diff --git a/test/unit/state_key_collation_activation.test.js b/test/unit/state_key_collation_activation.test.js deleted file mode 100644 index e59c873f..00000000 --- a/test/unit/state_key_collation_activation.test.js +++ /dev/null @@ -1,35 +0,0 @@ -// doctrine test-coverage program: unit coverage for -// src/state_key_collation_activation.js. Gates the contract-state state_key -// binary-collation flip that changes the contract_hash preimage, so an ungated -// or mis-resolved threshold forks against deployed nodes. Pins the per-chain -// resolution order (':' first, then bare network) and the -// fail-closed handling of unknown chains. - -const assert = require('assert'); -const { - STATE_KEY_COLLATION_ACTIVATION, isStateKeyBinCollationActive, -} = require('../../src/state_key_collation_activation.js'); - -describe('state_key_collation_activation', function () { - it('is armed from genesis on regtest', function () { - assert.strictEqual(STATE_KEY_COLLATION_ACTIVATION.regtest, 0); - assert.strictEqual(isStateKeyBinCollationActive(0, 'regtest'), true); - }); - - it('resolves the : key ahead of a bare network key', function () { - const t = STATE_KEY_COLLATION_ACTIVATION['BTC:mainnet']; - assert.ok(Number.isSafeInteger(t) && t > 0); - assert.strictEqual(isStateKeyBinCollationActive(t, 'mainnet', 'BTC'), true); - assert.strictEqual(isStateKeyBinCollationActive(t - 1, 'mainnet', 'BTC'), false); - }); - - it('uses per-coin thresholds (LTC and DOGE differ from BTC)', function () { - assert.ok(STATE_KEY_COLLATION_ACTIVATION['LTC:mainnet'] > 0); - assert.ok(STATE_KEY_COLLATION_ACTIVATION['DOGE:mainnet'] > 0); - }); - - it('fails closed (off) on an unknown chain or malformed height', function () { - assert.strictEqual(isStateKeyBinCollationActive(10 ** 12, 'mainnet', 'ZZZ'), false); - assert.strictEqual(isStateKeyBinCollationActive('bad', 'mainnet', 'BTC'), false); - }); -}); diff --git a/test/unit/train_activation.test.js b/test/unit/train_activation.test.js index 3b90d389..6b98abd0 100644 --- a/test/unit/train_activation.test.js +++ b/test/unit/train_activation.test.js @@ -34,7 +34,7 @@ const { resolveRuleSet, readManifestTrainActivation, evaluateTrainActivation -} = require('../../src/train_activation.js'); +} = require('../../src/consensus/gates/train_gate.js'); // The launch floor alone: a build that implements only rule set 1.0.0. const FLOOR = { '1.0.0': { mainnet: 0, testnet: 0, regtest: 0 } }; diff --git a/test/unit/train_activation_twin.test.js b/test/unit/train_activation_twin.test.js index 15027772..50254516 100644 --- a/test/unit/train_activation_twin.test.js +++ b/test/unit/train_activation_twin.test.js @@ -30,15 +30,15 @@ const assert = require('assert'); const fs = require('fs'); const path = require('path'); -const local = require('../../src/train_activation.js'); +const local = require('../../src/consensus/gates/train_gate.js'); // CI sets these to wherever it checked the siblings out; fall back to the dev // sibling layout one level above this repo. const DOCS_DIR = process.env.XCHAIN_DOCS_DIR || path.join(__dirname, '..', '..', '..', 'xchain-documentation'); const INDEXER_DIR = process.env.XCHAIN_INDEXER_DIR || path.join(__dirname, '..', '..', '..', 'xchain-indexer'); const CONSTANTS_PATH = path.join(DOCS_DIR, 'protocol', 'constants.js'); -const TWIN_PATH = path.join(INDEXER_DIR, 'src', 'train_activation.js'); -const HERE_PATH = path.resolve(__dirname, '..', '..', 'src', 'train_activation.js'); +const TWIN_PATH = path.join(INDEXER_DIR, 'src', 'consensus', 'gates', 'train_gate.js'); +const HERE_PATH = path.resolve(__dirname, '..', '..', 'src', 'consensus', 'gates', 'train_gate.js'); const SIBLING_REQUIRED = process.env.XCHAIN_REQUIRE_SIBLINGS === '1';