Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
283 commits
Select commit Hold shift + click to select a range
47b4b30
Assert complete resolveArgs refusal messages
jdogresorg Oct 4, 2026
0350571
Fix focused process resilience chaos cases
jdogresorg Oct 4, 2026
cabe608
Merge: test release asset exports
jdogresorg Oct 4, 2026
6f7c000
Merge: Pin clone call by arguments in git clone chaos tests
jdogresorg Oct 4, 2026
8bdb5f4
sync trunk
jdogresorg Oct 4, 2026
88d8125
Restore encoder process resilience scenarios
jdogresorg Oct 4, 2026
4f1a51f
Merge: Assert complete resolveArgs refusal messages
jdogresorg Oct 4, 2026
f392b32
Expect HTTPS modulesUrls clone in null-branch fuzz case
jdogresorg Oct 4, 2026
bd3fd45
Merge: Expect HTTPS modulesUrls clone in null-branch fuzz case
jdogresorg Oct 4, 2026
12760de
Honor per-coin hub seed configuration
jdogresorg Oct 4, 2026
cf63b8c
Merge: Honor per-coin hub seed configuration
jdogresorg Oct 4, 2026
4f2574f
Merge master (v0.22.3 hotfix) back into develop
jdogresorg Oct 4, 2026
bd0b8d5
Confirm develop CI recovery
jdogresorg Oct 4, 2026
4b29dae
Honor per-coin hub route precedence
jdogresorg Oct 4, 2026
020f2a6
Merge: Honor per-coin hub route precedence
jdogresorg Oct 4, 2026
8cc6fd6
sync trunk
jdogresorg Oct 4, 2026
dfbfd10
Preserve required Docker argument dependencies
jdogresorg Oct 5, 2026
b9a87c3
Fix config proxyquire stub keys
jdogresorg Oct 5, 2026
0a1b8aa
Mutate the split service modules and fail the scheduled run on an emp…
jdogresorg Oct 5, 2026
9cb483e
Cover split services in mutation runs
jdogresorg Oct 5, 2026
1118934
Pin Docker argument dependency fallbacks
jdogresorg Oct 5, 2026
6cdac10
Recover shared containers after redeploy
jdogresorg Oct 5, 2026
158e286
Merge: Fix config proxyquire stub keys
jdogresorg Oct 5, 2026
3aa4b4a
Add isolated bootstrap restore rehearsal
jdogresorg Oct 5, 2026
7589cde
sync trunk
jdogresorg Oct 5, 2026
29e8daa
sync trunk
jdogresorg Oct 5, 2026
0c84393
sync trunk
jdogresorg Oct 5, 2026
efc4363
Test stale hub container recovery
jdogresorg Oct 5, 2026
284307a
sync trunk
jdogresorg Oct 5, 2026
eeb16f3
Complete split-service mutation coverage
jdogresorg Oct 5, 2026
893a69c
Restore complete mutation operator coverage
jdogresorg Oct 5, 2026
e795958
Make module orchestration test hermetic
jdogresorg Oct 5, 2026
325a63a
Stub integration update target
jdogresorg Oct 5, 2026
f79b029
fix(pins): allow additive suite title growth
jdogresorg Oct 5, 2026
3aca3cd
test(pins): prove growth cannot mask drops
jdogresorg Oct 5, 2026
1b75db6
Merge: sync trunk
jdogresorg Oct 5, 2026
2b848d5
Merge: Stub integration update target
jdogresorg Oct 5, 2026
ea474f0
sync trunk
jdogresorg Oct 5, 2026
23b63f6
sync trunk
jdogresorg Oct 5, 2026
9d6acee
sync trunk
jdogresorg Oct 5, 2026
ee6000a
Test Docker argument dependency fallbacks
jdogresorg Oct 5, 2026
6da908b
sync trunk
jdogresorg Oct 5, 2026
59f22c5
Restore original Stryker test order
jdogresorg Oct 5, 2026
0d4a669
Use a public bootstrap rehearsal database name
jdogresorg Oct 5, 2026
c86a03d
Limit stale container recovery to hub
jdogresorg Oct 5, 2026
91cd5cf
Merge: Test Docker argument dependency fallbacks
jdogresorg Oct 5, 2026
646c98b
Merge: Restore original Stryker test order
jdogresorg Oct 5, 2026
33ec580
Merge: Use a public bootstrap rehearsal database name
jdogresorg Oct 5, 2026
33e4a15
sync trunk
jdogresorg Oct 5, 2026
cbf0643
Align fuzz tests with strict runtime contracts
jdogresorg Oct 5, 2026
cb9038d
Align process resilience chaos contracts
jdogresorg Oct 5, 2026
28ea0f1
Keep hub regression within structure limits
jdogresorg Oct 5, 2026
6d5e384
sync trunk
jdogresorg Oct 5, 2026
99e7ca1
Fix dependency fallback test isolation
jdogresorg Oct 5, 2026
ed8bbb5
Remove unrelated fuzz contract rewrites
jdogresorg Oct 5, 2026
a57c477
sync trunk
jdogresorg Oct 5, 2026
bed6022
Refresh additive suite title pin
jdogresorg Oct 5, 2026
f0a89e9
Merge: Align process resilience chaos contracts
jdogresorg Oct 5, 2026
2469b14
Merge: Keep hub regression within structure limits
jdogresorg Oct 5, 2026
b260d1c
Merge: Fix dependency fallback test isolation
jdogresorg Oct 5, 2026
671c579
Keep active split records blocking
jdogresorg Oct 5, 2026
c7e042b
sync trunk
jdogresorg Oct 5, 2026
ab78c30
Enforce additive suite title comparisons
jdogresorg Oct 5, 2026
2288791
sync trunk
jdogresorg Oct 5, 2026
174973a
Remove unrelated chaos dependency overrides
jdogresorg Oct 5, 2026
adcc8d5
sync trunk
jdogresorg Oct 5, 2026
5ec3644
Align fuzz environment contracts
jdogresorg Oct 5, 2026
08afe95
Derive satisfied indexer ledger rows for a from-genesis reset
jdogresorg Oct 5, 2026
272f7bc
Require Error container ID rejections
jdogresorg Oct 5, 2026
0c367fb
Clarify MariaDB precheck success stub
jdogresorg Oct 5, 2026
a870ada
Restore container ID rejection contract
jdogresorg Oct 5, 2026
426e4ff
Merge: Enforce additive suite title comparisons
jdogresorg Oct 5, 2026
8e35791
Align e2e scenarios with current contracts
jdogresorg Oct 5, 2026
75a52b6
Merge: Derive satisfied indexer ledger rows for a from-genesis reset
jdogresorg Oct 5, 2026
d5ce5e5
sync trunk
jdogresorg Oct 5, 2026
96d9004
Narrow e2e coverage to environment contract
jdogresorg Oct 5, 2026
47975a7
Merge: Clarify MariaDB precheck success stub
jdogresorg Oct 5, 2026
4a121ef
sync trunk
jdogresorg Oct 5, 2026
2e9ac0d
sync trunk
jdogresorg Oct 5, 2026
3f4911e
Assert string container ID rejections
jdogresorg Oct 5, 2026
74ca601
Update e2e scenarios to the current module-ops contracts
jdogresorg Oct 5, 2026
ef4971b
Keep install lifecycle scenario within the file line limit
jdogresorg Oct 5, 2026
0ad61cb
Restore full all-module update coverage in the e2e update flow
jdogresorg Oct 5, 2026
eb299f4
Tighten update replacement command coverage
jdogresorg Oct 5, 2026
1936fea
Keep fuzz env comments within the block cap and preserve comment cove…
jdogresorg Oct 5, 2026
40b9d72
Keep passing env escaping fuzz cases unchanged and assert the env con…
jdogresorg Oct 5, 2026
d876175
Align update scenario label with graceful stop
jdogresorg Oct 5, 2026
6e2ed3a
Merge: Keep passing env escaping fuzz cases unchanged and assert the …
jdogresorg Oct 5, 2026
a478ddf
Isolate update preflight guards in the e2e harness
jdogresorg Oct 5, 2026
0593788
sync trunk
jdogresorg Oct 5, 2026
809b0d2
Apply container resource overrides consistently
jdogresorg Oct 5, 2026
0cc6ae5
Apply container limits during creation
jdogresorg Oct 5, 2026
f51afb7
Preserve E2E contract comments
jdogresorg Oct 5, 2026
a8b7bdb
Extract container run argument helpers
jdogresorg Oct 5, 2026
f9f7d1a
Merge: Extract container run argument helpers
jdogresorg Oct 5, 2026
85d40df
sync trunk
jdogresorg Oct 5, 2026
c9ce779
Restore original E2E contract comments
jdogresorg Oct 5, 2026
8c4e473
Merge master (v0.22.4 hotfix) back into develop
jdogresorg Oct 5, 2026
e61770b
Move the generated DOGE signer environment reads into config
jdogresorg Oct 5, 2026
0f885c8
sync trunk
jdogresorg Oct 5, 2026
9b7ad97
Trim install_lifecycle e2e file back under the 400 line limit
jdogresorg Oct 5, 2026
55114a7
sync trunk
jdogresorg Oct 5, 2026
982a5b0
Merge: Trim install_lifecycle e2e file back under the 400 line limit
jdogresorg Oct 5, 2026
4236064
Merge: sync trunk
jdogresorg Oct 5, 2026
2509268
Collect the boundary test tier in npm run ci
jdogresorg Oct 4, 2026
6f79270
Stop the service before a bootstrap restore when the registry lookup …
jdogresorg Oct 6, 2026
7449779
Read the decoder reorg halt from a plain body or a JSON-RPC result en…
jdogresorg Oct 6, 2026
0f6f22c
Make the boundary tier's fs stubs complete
jdogresorg Oct 6, 2026
2124265
Merge: Read the decoder reorg halt from a plain body or a JSON-RPC re…
jdogresorg Oct 6, 2026
cb731be
sync trunk
jdogresorg Oct 6, 2026
0eae6a9
sync trunk
jdogresorg Oct 6, 2026
9f355fe
Read the node's remote release tag in the menu, gate release hashes b…
jdogresorg Oct 6, 2026
337d2bc
Refuse a bootstrap restore only after archive verification, validate …
jdogresorg Oct 6, 2026
c63ba29
sync trunk
jdogresorg Oct 6, 2026
df6f9c0
sync trunk
jdogresorg Oct 6, 2026
d99956d
Merge develop: restore package.json to develop
jdogresorg Oct 6, 2026
495c556
Merge: Merge develop: restore package.json to develop
jdogresorg Oct 6, 2026
5abd6c3
Run the e2e suite with whichever preflight file the ref carries
jdogresorg Oct 6, 2026
9c8556d
sync trunk
jdogresorg Oct 6, 2026
178bf01
Merge: Run the e2e suite with whichever preflight file the ref carries
jdogresorg Oct 6, 2026
f06b425
Collect the boundary test tier in the ci script
jdogresorg Oct 6, 2026
4f98eca
sync trunk
jdogresorg Oct 6, 2026
5d1ecd7
Merge master (v0.22.5 hotfix) back into develop
jdogresorg Oct 6, 2026
9dc2fee
Add the CLA Assistant step to the PR checklist
jdogresorg Oct 6, 2026
1b2f765
Merge: Collect the boundary test tier in the ci script
jdogresorg Oct 6, 2026
06be19f
Merge: Add the CLA Assistant step to the PR checklist
jdogresorg Oct 6, 2026
6fba4ea
sync trunk
jdogresorg Oct 6, 2026
231f2c0
sync trunk
jdogresorg Oct 6, 2026
772c7e9
Give the bootstrap test db stub a strict container lookup that follow…
jdogresorg Oct 6, 2026
f1d5ace
Give the bootstrap health gate test db stubs a strict container lookup
jdogresorg Oct 6, 2026
5abd8d5
Merge: Give the bootstrap health gate test db stubs a strict containe…
jdogresorg Oct 6, 2026
991fe20
Merge master (v0.22.6 hotfix) back into develop
jdogresorg Oct 6, 2026
d10f317
Run the fuzz, chaos and e2e tiers in npm run ci and stub readFileSync…
jdogresorg Oct 6, 2026
4410e1b
sync trunk
jdogresorg Oct 6, 2026
d2bd352
Pin the chaos config tests to a stub database service so they no long…
jdogresorg Oct 6, 2026
97483af
Merge: Pin the chaos config tests to a stub database service so they …
jdogresorg Oct 6, 2026
ac74062
Wire the integration tier into npm run ci and stub the hub consensus …
jdogresorg Oct 6, 2026
d5c9d33
Merge: Wire the integration tier into npm run ci and stub the hub con…
jdogresorg Oct 6, 2026
39ab69f
Move database service suites into external_db, watermark and build_mo…
jdogresorg Oct 6, 2026
a484f8f
Move docker service error-branch and monitor suites into topic subdir…
jdogresorg Oct 6, 2026
7c5c414
Move autoheal backoff and probation suites into topic subdirectories
jdogresorg Oct 6, 2026
c692467
Move the reset and update module operation suites into topic subdirec…
jdogresorg Oct 6, 2026
e3731db
Merge: Move database service suites into external_db, watermark and b…
jdogresorg Oct 6, 2026
436be04
Merge: Move autoheal backoff and probation suites into topic subdirec…
jdogresorg Oct 6, 2026
d739c94
Merge: Move docker service error-branch and monitor suites into topic…
jdogresorg Oct 6, 2026
2b8fa40
Merge: Move the reset and update module operation suites into topic s…
jdogresorg Oct 6, 2026
21c3470
Merge master (v0.22.7 hotfix) back into develop
jdogresorg Oct 6, 2026
b8ef7d1
Drop the encoder from autoheal since its probe 503s on a tracker halt…
jdogresorg Oct 7, 2026
cf03056
Make update all continue past a guard refusal
jdogresorg Oct 7, 2026
65e7b07
Make the node container actions in the module menu rebuild the node
jdogresorg Oct 7, 2026
685149c
sync trunk
jdogresorg Oct 7, 2026
6951c07
Keep encoder autoheal coverage within structure limits
jdogresorg Oct 7, 2026
1e3cf5f
sync trunk
jdogresorg Oct 7, 2026
55d1ea2
sync trunk
jdogresorg Oct 7, 2026
0c1c3aa
Review round 2026-10-06: 5 review fixes in xchain-node
jdogresorg Oct 7, 2026
a3d75a8
Merge: Keep encoder autoheal coverage within structure limits
jdogresorg Oct 7, 2026
859c060
Merge: sync trunk
jdogresorg Oct 7, 2026
123e973
Merge: sync trunk
jdogresorg Oct 7, 2026
7fba6f6
Clarify attribution license term
jdogresorg Oct 7, 2026
cd788dc
Review round 2026-10-06, second pass: 1 review fix in xchain-node
jdogresorg Oct 7, 2026
b6117a1
Review round 2026-10-06, third pass: 1 review fix in xchain-node
jdogresorg Oct 7, 2026
e2faed1
Guard coin node bind mount sources
jdogresorg Oct 7, 2026
feebe22
Review round 2026-10-06, fourth pass: 2 review fixes in xchain-node
jdogresorg Oct 7, 2026
9e6c903
sync trunk
jdogresorg Oct 7, 2026
bb6ac24
Merge: Clarify attribution license term
jdogresorg Oct 7, 2026
887a34d
sync trunk
jdogresorg Oct 7, 2026
15217e3
Guard datadir mount source drift
jdogresorg Oct 7, 2026
5eeb628
Merge: Guard datadir mount source drift
jdogresorg Oct 7, 2026
a7bb64c
Stabilize hub network config test
jdogresorg Oct 7, 2026
8393402
Merge: Stabilize hub network config test
jdogresorg Oct 7, 2026
d25067a
Give coverage tests runner headroom
jdogresorg Oct 7, 2026
e7dcbdd
Harden coin conformance sibling guard
jdogresorg Oct 7, 2026
59ad265
Isolate config tests from database lookup
jdogresorg Oct 7, 2026
ebeb719
Merge: Harden coin conformance sibling guard
jdogresorg Oct 7, 2026
cf28b8a
Compose co-located LTC and DOGE indexer URLs for the hub
jdogresorg Oct 7, 2026
b373a64
sync trunk
jdogresorg Oct 7, 2026
912bd3d
Wire co-located indexer URLs into hub config
jdogresorg Oct 7, 2026
b872674
Keep hub config networks module within structure limits
jdogresorg Oct 7, 2026
8bfdd2a
fix(node): preserve container environment on recreate
jdogresorg Oct 7, 2026
3286e22
fix(node): keep stop budget import unchanged
jdogresorg Oct 7, 2026
becc96b
Prefer Docker DNS for co-located hub indexers
jdogresorg Oct 7, 2026
9f0faaf
Cover colocated hub indexer URLs
jdogresorg Oct 8, 2026
44b0d93
Preserve indexer URLs for ambiguous hub networks
jdogresorg Oct 8, 2026
8914d20
Fix node shared-service uninstall and attest-mirror leg findings
jdogresorg Oct 8, 2026
5747fab
Block stake teardown on a sleeping source address
jdogresorg Oct 8, 2026
8456c6c
sync trunk
jdogresorg Oct 8, 2026
c661958
sync trunk
jdogresorg Oct 8, 2026
5c83d0f
Recognize repaired mirror cursor ids
jdogresorg Oct 8, 2026
6bc0929
Match mirror cursor repair predicate exactly
jdogresorg Oct 8, 2026
9061b56
Keep mirror repair coverage within reset tests
jdogresorg Oct 8, 2026
f74942c
Re-sync the coin registry from the canonical xchain-hub/src/coins
jdogresorg Oct 8, 2026
a983404
Re-take the identity pin for the re-synced coin registry
jdogresorg Oct 8, 2026
dfbf213
Merge: Preserve indexer URLs for ambiguous hub networks
jdogresorg Oct 8, 2026
89eb602
Merge: fix(node): keep stop budget import unchanged
jdogresorg Oct 8, 2026
bced378
fix(node): preserve drift guard executor injection
jdogresorg Oct 8, 2026
d491c50
Fail closed when latest release lookup errors
jdogresorg Oct 8, 2026
ebe9941
sync trunk
jdogresorg Oct 8, 2026
7c0eb79
Restore the coverage test timeout
jdogresorg Oct 8, 2026
d83c030
Merge: Restore the coverage test timeout
jdogresorg Oct 8, 2026
96c5250
Merge: fix(node): preserve drift guard executor injection
jdogresorg Oct 8, 2026
04094dc
Merge: Fail closed when latest release lookup errors
jdogresorg Oct 8, 2026
84a7481
fix: review round corrections
jdogresorg Oct 8, 2026
435cb36
test: split the configured database name cases into named helpers
jdogresorg Oct 8, 2026
73b2cbe
Wait for indexer schema readiness signal
jdogresorg Oct 9, 2026
2cf694a
Split schema readiness test groups
jdogresorg Oct 9, 2026
0a042cf
Merge reviewed lane work into develop
jdogresorg Oct 9, 2026
18660fc
publish-bootstraps: skip the run while the roll hold file exists
jdogresorg Oct 9, 2026
865eaa1
Recognize UNARMED go-live sentinels
jdogresorg Oct 9, 2026
ec9a271
Narrow UNARMED sentinel scope
jdogresorg Oct 9, 2026
755a774
Exercise UNARMED scanner behavior
jdogresorg Oct 9, 2026
dc3a356
Merge: publish-bootstraps: skip the run while the roll hold file exists
jdogresorg Oct 9, 2026
b1f96a5
Split go-live scanner test suites
jdogresorg Oct 9, 2026
513e600
Merge: Split go-live scanner test suites
jdogresorg Oct 9, 2026
b9304e8
Report failed health probe responses
jdogresorg Oct 9, 2026
2319f37
Use stdout for health probe diagnostics
jdogresorg Oct 9, 2026
541e76c
Merge: Use stdout for health probe diagnostics
jdogresorg Oct 9, 2026
4e17d40
Mark package as private
jdogresorg Oct 9, 2026
d739477
Merge: Mark package as private
jdogresorg Oct 9, 2026
103e41a
Fix 11 review findings in xchain-node
jdogresorg Oct 9, 2026
15f5d7d
Preserve bootstrap refusal diagnostics
jdogresorg Oct 9, 2026
b44273d
Make self-update lock handoff atomic
jdogresorg Oct 9, 2026
a724135
Accept pinned sibling main checkouts
jdogresorg Oct 9, 2026
1e2d4b9
Split refusal-reason test helper out of the describe block
jdogresorg Oct 9, 2026
111019a
Split lock handoff helpers for structure checks
jdogresorg Oct 9, 2026
faaa777
Allow overriding the database host port
jdogresorg Oct 9, 2026
04c3e03
Generate database passwords per install
jdogresorg Oct 9, 2026
f5b111f
Shard nightly action matrix six ways
jdogresorg Oct 9, 2026
3a70710
Release self-update lock before re-exec
jdogresorg Oct 9, 2026
491fe33
Merge bootstrap publish refusal reason
jdogresorg Oct 9, 2026
8e7ea23
Merge database host port override
jdogresorg Oct 9, 2026
0e8f533
Merge per-install database passwords
jdogresorg Oct 9, 2026
23b4ade
Merge six e2e shards per coin
jdogresorg Oct 9, 2026
b01670a
Grant exact mainnet HubMirror access
jdogresorg Oct 9, 2026
34a5686
Split provisioning tests within structure limits
jdogresorg Oct 9, 2026
c079148
Merge: Accept pinned sibling main checkouts
jdogresorg Oct 9, 2026
bef206f
Merge: Release self-update lock before re-exec
jdogresorg Oct 10, 2026
63a2c7b
Merge: Split provisioning tests within structure limits
jdogresorg Oct 10, 2026
f7395db
Update database credential contract tests
jdogresorg Oct 10, 2026
088938f
Merge: Update database credential contract tests
jdogresorg Oct 10, 2026
dc47a26
Set the repo git identity at session start and turn attribution off
jdogresorg Oct 10, 2026
034ab22
Update R-E2E-006 for the probe-free credential rotation check
jdogresorg Oct 11, 2026
2ae9c9d
Merge: Update R-E2E-006 for the probe-free credential rotation check
jdogresorg Oct 11, 2026
624cce3
Give the config chaos experiments the sidecar fs calls and a writable…
jdogresorg Oct 11, 2026
6804722
Seed the attest-mirror stack hub with each indexer's database coordin…
jdogresorg Oct 11, 2026
488e97b
Merge: Seed the attest-mirror stack hub with each indexer's database …
jdogresorg Oct 11, 2026
07e06bb
Raise the attest-mirror stack indexers' rate limit
jdogresorg Oct 11, 2026
6c22602
Wait for the attest-mirror stack explorer before calling the stack ready
jdogresorg Oct 11, 2026
c06ee35
Release v0.23.0
jdogresorg Oct 11, 2026
bbd3e6a
Record the v0.23.0 release manifest
jdogresorg Oct 12, 2026
9a3f880
Merge pull request #67 from XChain-Platform/release-manifest-v0.23.0
jdogresorg Oct 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"attribution": false,
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "git config user.name 'J-Dog' && git config user.email 'j-dog@j-dog.net' || true",
"timeout": 10,
"statusMessage": "Setting the repo git identity"
}
]
}
]
}
}
7 changes: 7 additions & 0 deletions .github/attest-mirror/compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,11 @@ services:
INDEXER_COIN: BTC
INDEXER_NETWORK: regtest
INDEXER_API_PORT: 3004
# Every host-side caller (the venue's five hubs, its indexers and the suite)
# reaches this indexer through the published port from one source address, so
# the per-IP default of 600 a minute is spent in about 40 s and the hubs' tip
# reads are refused for the rest of each window. The same applies to LTC and DOGE.
INDEXER_RATE_LIMIT_RPM: 99999
INDEXER_DB_HOST: db
INDEXER_DB_PORT: 3306
INDEXER_DB_NAME: XChain_BTC_Regtest_Indexer
Expand Down Expand Up @@ -409,6 +414,7 @@ services:
INDEXER_COIN: LTC
INDEXER_NETWORK: regtest
INDEXER_API_PORT: 3004
INDEXER_RATE_LIMIT_RPM: 99999
INDEXER_DB_HOST: db
INDEXER_DB_PORT: 3306
INDEXER_DB_NAME: XChain_LTC_Regtest_Indexer
Expand Down Expand Up @@ -592,6 +598,7 @@ services:
INDEXER_COIN: DOGE
INDEXER_NETWORK: regtest
INDEXER_API_PORT: 3004
INDEXER_RATE_LIMIT_RPM: 99999
INDEXER_DB_HOST: db
INDEXER_DB_PORT: 3306
INDEXER_DB_NAME: XChain_DOGE_Regtest_Indexer
Expand Down
2 changes: 1 addition & 1 deletion .github/attest-mirror/run-leg.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ for p in "$BTC_NODE_PORT" "$LTC_NODE_PORT" "$DOGE_NODE_PORT"; do
done
cd "${ATTEST_MIRROR_E2E_DIR:-$root/xchain-e2e-test}"
printf "=== leg %s start %s node %s stack xca7%s venue-base %s file %s extra-env [%s]\n" "$tag" "$(date -u +%FT%TZ)" "$(node -v)" "$stack" "$venue_base" "$leg" "$*"
env "$@" npx mocha --timeout 0 --exit --require ./test/initialCheck.test.js "$leg" 2>&1 | node -e 'const rl=require("readline").createInterface({input:process.stdin});rl.on("line",l=>process.stdout.write(new Date().toISOString().slice(11,19)+" "+l+"\n"))'
env "$@" npx mocha --timeout 0 --exit --require ./test/initial_check.test.js "$leg" 2>&1 | node -e 'const rl=require("readline").createInterface({input:process.stdin});rl.on("line",l=>process.stdout.write(new Date().toISOString().slice(11,19)+" "+l+"\n"))'
rc=${PIPESTATUS[0]}
printf "=== leg %s exit=%s end %s\n" "$tag" "$rc" "$(date -u +%FT%TZ)"
exit "$rc"
6 changes: 5 additions & 1 deletion .github/attest-mirror/seed-stack-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ const port = Number(process.argv[2]);
const pass = process.env.DB_PASSWORD;
if (!port || !pass) process.exit(2);
const ixHost = { BTC: 'indexer', LTC: 'ltc-indexer', DOGE: 'doge-indexer' };
// The indexer entry's host and port are its API; db_host and db_port say where its
// database lives. The explorer builds its pools from db_host/db_port and falls back to
// host/port without them, so it would dial the indexer API as MariaDB and never serve.
function services(code) {
return {
'xchain-decoder': { host: 'db', port: '3306', name: `XChain_${code}_Regtest_Decoder`, user: 'root', pass },
'xchain-indexer': { host: ixHost[code], port: '3004', name: `XChain_${code}_Regtest_Indexer`, user: 'root', pass }
'xchain-indexer': { host: ixHost[code], port: '3004', db_host: 'db', db_port: '3306',
name: `XChain_${code}_Regtest_Indexer`, user: 'root', pass }
};
}
const config = {
Expand Down
20 changes: 20 additions & 0 deletions .github/attest-mirror/setup-stack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,26 @@ for _ in $(seq 1 180); do
set +a
node "$root/seed-stack-config.js" "$HUB_HOST_PORT"
node "$root/wait-indexer-schema.js"
# The explorer answers ping 503 until its next hub config poll picks up the coins
# seeded above, which can trail a warm boot by a minute. A suite that pings it
# first fails its initial check, so the stack is ready only once it answers.
explorer_ping='{"jsonrpc":"2.0","method":"ping","id":1}'
explorer_ok=0
for _ in $(seq 1 120); do
if curl -fsS -o /dev/null -H 'content-type: application/json' --data "$explorer_ping" \
"http://127.0.0.1:$EXPLORER_HTTP_HOST_PORT/" 2>/dev/null; then
explorer_ok=1
break
fi
sleep 2
done
if [ "$explorer_ok" != 1 ]; then
date -u
printf "explorer=%s\n" "$(health explorer)"
printf "explorer ping timeout for xca7%s\n" "$stack"
exit 1
fi
printf "explorer ready\n"
date -u
exit 0
fi
Expand Down
113 changes: 92 additions & 21 deletions .github/attest-mirror/wait-indexer-schema.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,94 @@
'use strict';
// Venue warm-up: waits until the stack indexer's schema exists (issues table) and its /status answers, so a leg's
// initialCheck ISSUE never races the indexer's first migration. Credentials come from the stack .env via env.
const mariadb = require('module').createRequire(require('path').join(process.env.ATTEST_MIRROR_E2E_DIR, 'package.json'))('mariadb');
const waitMs = Number(process.env.ATTEST_SCHEMA_WAIT_MS || 1200000);
const deadline = Date.now() + waitMs;
(async () => {
'use strict'

const path = require('path')
const { createRequire } = require('module')

const DATABASE = 'XChain_BTC_Regtest_Indexer'
const TABLE = 'issues'
const DEFAULT_WAIT_MS = 1200000
const DEFAULT_INTERVAL_MS = 3000

function loadMariadb (env) {
return createRequire(path.join(env.ATTEST_MIRROR_E2E_DIR, 'package.json'))('mariadb')
}

async function issuesTableReady (config) {
let connection = null
try {
connection = await config.connect(config.dbOptions)
const rows = await connection.query(
"SELECT COUNT(*) AS n FROM information_schema.tables WHERE table_schema = '" +
DATABASE + "' AND table_name = '" + TABLE + "'")
return Number(rows[0].n) === 1
} catch (_) {
return false
} finally {
if (connection) await connection.end().catch(() => {})
}
}

async function schemaReady (config) {
let body
try {
const response = await config.fetchImpl(config.statusUrl)
if (!response || !response.ok) return false
body = await response.json()
} catch (_) {
return false
}
if (!body || typeof body !== 'object') return false
if (Object.prototype.hasOwnProperty.call(body, 'schemaReady')) return body.schemaReady === true
return issuesTableReady(config)
}

async function waitForSchema (config) {
const deadline = config.now() + config.waitMs
for (;;) {
let ok = false;
try {
const options = { host: '127.0.0.1', port: Number(process.env.DB_HOST_PORT), user: 'root' };
options['pass' + 'word'] = process.env['DB_' + 'PASSWORD'];
const c = await mariadb.createConnection(options);
const rows = await c.query("SELECT COUNT(*) AS n FROM information_schema.tables WHERE table_schema = 'XChain_BTC_Regtest_Indexer' AND table_name = 'issues'");
await c.end();
const res = await fetch(`http://127.0.0.1:${process.env.INDEXER_HOST_PORT}/status`).catch(() => null);
ok = Number(rows[0].n) === 1 && !!res && res.ok;
} catch (e) { ok = false; }
if (ok) { console.log('indexer schema ready'); return; }
if (Date.now() > deadline) { console.log('indexer schema NOT ready after ' + Math.round(waitMs / 1000) + ' s'); process.exit(5); }
await new Promise((r) => setTimeout(r, 3000));
if (await schemaReady(config)) return true
if (config.now() > deadline) return false
await config.sleep(config.intervalMs)
}
}

function configFromEnv (env, dependencies) {
const dbOptions = { host: '127.0.0.1', port: Number(env.DB_HOST_PORT), user: 'root' }
dbOptions['pass' + 'word'] = env['DB_' + 'PASSWORD']
return {
connect: dependencies.mariadb.createConnection,
dbOptions,
fetchImpl: dependencies.fetchImpl,
statusUrl: 'http://127.0.0.1:' + env.INDEXER_HOST_PORT + '/status',
waitMs: Number(env.ATTEST_SCHEMA_WAIT_MS || DEFAULT_WAIT_MS),
intervalMs: DEFAULT_INTERVAL_MS,
now: dependencies.now || Date.now,
sleep: dependencies.sleep || ((ms) => new Promise((resolve) => setTimeout(resolve, ms))),
}
}

async function main (runtime) {
const context = runtime || {}
const env = context.env || process.env
const mariadb = context.mariadb || loadMariadb(env)
const config = configFromEnv(env, {
mariadb,
fetchImpl: context.fetchImpl || fetch,
now: context.now,
sleep: context.sleep,
})
const log = context.log || console.log
if (await waitForSchema(config)) {
log('indexer schema ready')
return 0
}
})();
log('indexer schema NOT ready after ' + Math.round(config.waitMs / 1000) + ' s')
return 5
}

if (require.main === module) {
main().then((code) => { process.exitCode = code }).catch((error) => {
console.error(error.message)
process.exitCode = 5
})
}

module.exports = { DATABASE, TABLE, issuesTableReady, schemaReady, waitForSchema, configFromEnv, main }
19 changes: 19 additions & 0 deletions .github/hub-failover/compose.testnet-ids.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
services:
hub-a:
environment:
P2P_VALIDATOR_ADDR: mverify5szar1XwwAjqAnPUHbA814kfHh4

hub-b:
environment:
P2P_VALIDATOR_ADDR: mverify7szar1XwwAjqAnPUHbA814kfHh4

hub-federation-init:
command:
- |
for hub in hub-a hub-b; do
for registration in \
'{"jsonrpc":"2.0","id":1,"method":"registervalidator","params":{"signing_pubkey":"03a107bff3ce10be1d70dd18e74bc09967e4d6309ba50d5f1ddc8664125531b8","addr":"mverify5szar1XwwAjqAnPUHbA814kfHh4"}}' \
'{"jsonrpc":"2.0","id":2,"method":"registervalidator","params":{"signing_pubkey":"29acbae141bccaf0b22e1a94d34d0bc7361e526d0bfe12c89794bc9322966dd7","addr":"mverify7szar1XwwAjqAnPUHbA814kfHh4"}}'; do
wget -qO- --header="x-api-key: $${HUB_API_KEY}" --header="Content-Type: application/json" --post-data="$${registration}" "http://$${hub}:10000/" | grep -q '"status":"success"'
done
done
6 changes: 5 additions & 1 deletion .github/workflows/mutation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,15 @@ jobs:
- name: Run Stryker
run: npm run test:mutation

- name: Verify mutation reports
if: always()
run: test -s reports/mutation/report.json && test -s reports/mutation/index.html

- name: Upload mutation report
if: always()
uses: actions/upload-artifact@v4
with:
name: mutation-report
path: reports/mutation/
if-no-files-found: warn
if-no-files-found: error
retention-days: 30
14 changes: 7 additions & 7 deletions .github/workflows/nightly-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ permissions:
#
# A shard is a fresh stack, so every suite already had to be runnable alone
# (the `suite` input has always relied on that); sharding adds no new ordering
# assumption. Five shards bring the bitcoin weights to ~42 minutes of action
# assumption. Six shards bring the bitcoin weights to ~34 minutes of action
# per shard, about an hour per job with setup and boot.
jobs:
plan:
Expand All @@ -176,10 +176,10 @@ jobs:
env:
STACK_REF: ${{ github.event.inputs.ref || 'develop' }}
SUITE: ${{ github.event.inputs.suite || '' }}
# Sized off run 35605562229: ~204 minutes of bitcoin action weight over 5
# shards is ~42 each. Raise it here if the suite grows; nothing else
# hardcodes the count. Three coins at 5 shards is 15 concurrent runners.
E2E_SHARDS: '5'
# Sized off run 35605562229: ~204 minutes of bitcoin action weight over 6
# shards is ~34 each. Raise it here if the suite grows; nothing else
# hardcodes the count. Three coins at 6 shards is 18 concurrent runners.
E2E_SHARDS: '6'
steps:
# The plan and merge scripts come from THIS workflow's commit, not from
# the ref under test, so an older ref (a published vX.Y.Z) that predates
Expand Down Expand Up @@ -235,9 +235,9 @@ jobs:
coin: ${{ fromJSON(needs.plan.outputs.coins) }}
shard: ${{ fromJSON(needs.plan.outputs.shards) }}
# 360 was the unsharded ceiling, set because a whole coin pass had no
# measured duration to size against. A shard does: ~42 minutes of action
# measured duration to size against. A shard does: ~34 minutes of action
# plus ~15 of setup and boot on bitcoin, somewhat more on the two-stack
# legs. 240 is four times that, so a slow leg is never truncated, while a
# legs. 240 is about five times that, so a slow leg is never truncated, while a
# WEDGED shard (a hung container, a stalled indexer poll) reports in four
# hours instead of six.
timeout-minutes: 240
Expand Down
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.23.0] - 2026-10-11

### Added
- Added co-located indexer URLs to the hub config and honored per-coin hub seed and route settings.
- Added an isolated bootstrap restore rehearsal and recovery of shared containers after a redeploy.
- Recognized the UNARMED go-live sentinels in the release guards.

### Changed
- Applied container limits and resource overrides consistently at creation.
- Made update all continue past a guard refusal and failed closed when the latest release lookup errors.

### Fixed
- Guarded coin node and datadir bind mount sources against drift.
- Preserved the container environment on recreate and blocked stake teardown on a sleeping source address.
- Dropped the encoder from autoheal because a restart cannot clear a tracker halt.

## [0.22.7] - 2026-10-06

### Changed
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ CI is the unit gate. Before opening a PR:
2. Update `CHANGELOG.md` with a terse entry for your change.
3. Make sure `git status` is clean apart from intended changes (no `node_modules/`, no editor leftovers, no generated `.env` files).
4. Open the PR with a clear title and a description of what changed and why.
5. The CLA Assistant bot records your signature on your first PR; one signature covers every XChain Platform repository. Its `license/cla` check must pass before the PR can merge.

For non-security bugs, open an issue at <https://github.com/XChain-Platform/xchain-node/issues/new>. For security bugs, see [`SECURITY.md`](./SECURITY.md).

Expand Down
6 changes: 4 additions & 2 deletions NOTICE.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ For commercial licensing, contact **legal@dankest.llc**.

## Attribution

Any redistribution or modification of this software must retain the following
attribution, per the AGPL and the project's trademark policy:
As an additional term under section 7(b) of the GNU Affero General Public
License v3.0, any redistribution or modification of this software must preserve
the following author attribution in its source and in the Appropriate Legal
Notices displayed by any work containing it:

> Based on XChain Platform by Dankest, LLC - https://dankest.llc

Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,15 +136,17 @@ When xchain-node manages its own MariaDB container, these optional env vars over

## Autoheal (restart-on-unhealthy)

Every persistent service container carries a Docker healthcheck, but Docker itself takes no action on the `unhealthy` state (`--restart unless-stopped` only fires when the process exits). An alive-but-stalled service would otherwise stay wedged until an operator notices it in `docker ps`. `xchain-node autoheal` closes that loop: it restarts containers that have been continuously unhealthy past a grace window, for services opted in via `autoheal: true` in the healthcheck table (currently the decoder, encoder, and indexer; the utxo-tracker is deliberately excluded because it halts on purpose rather than exiting, and a restart would just re-halt it).
Every persistent service container carries a Docker healthcheck, but Docker itself takes no action on the `unhealthy` state (`--restart unless-stopped` only fires when the process exits). An alive-but-stalled service would otherwise stay wedged until an operator notices it in `docker ps`. `xchain-node autoheal` closes that loop: it restarts containers that have been continuously unhealthy past a grace window, for services opted in via `autoheal: true` in the healthcheck table (currently the decoder and indexer; the utxo-tracker is deliberately excluded because it halts on purpose rather than exiting, and a restart would just re-halt it; the encoder is deliberately excluded because its health probe reports utxo-tracker readiness (unreachable, halted, lagging or mempool not ready), which restarting the encoder cannot clear).

The command is one-shot and never prompts or daemonizes. Unattended remediation requires wiring it to a cron entry or systemd timer, e.g. `*/5 * * * * xchain_node autoheal`. Detection-to-restart latency is the timer interval plus the health retry budget plus the grace window. Use `--dry-run` to see restart candidates without acting. Exit code is non-zero only when a restart was attempted and failed.

| Variable | Default | What it controls |
|---|---|---|
| `XCHAIN_NODE_AUTOHEAL_GRACE_MS` | `120000` | How long a container must be continuously unhealthy before a restart is considered |
| `XCHAIN_NODE_AUTOHEAL_COOLDOWN_MS` | `600000` | Minimum time between two autoheal restarts of the same container (anti-flap) |
| `XCHAIN_NODE_AUTOHEAL_STATE_DIR` | `~/.xchain-node` | Where the anti-flap state file (`autoheal-state.json`) lives |
| `XCHAIN_NODE_AUTOHEAL_COOLDOWN_MS` | `600000` | Base wait before autoheal restarts the same container again (anti-flap). The first retry waits this long; each further restart of a container that has not recovered doubles the wait, up to `XCHAIN_NODE_AUTOHEAL_COOLDOWN_CEILING_MS` (with defaults: 10m, 20m, 40m and so on, capped at 6h). The doubling resets once the container recovers |
| `XCHAIN_NODE_AUTOHEAL_COOLDOWN_CEILING_MS` | `21600000` | Upper bound on the doubled cooldown. A container that never recovers settles at one restart per ceiling; there is no attempt cap, and every skipped pass logs an "investigate" line |
| `XCHAIN_NODE_AUTOHEAL_PROBATION_MS` | `150000` | How long after an autoheal restart a passing health probe counts as that restart's own artifact rather than recovery, so it does not reset the backoff. If you widen a service's start period with `XCHAIN_NODE_HEALTH_START_PERIOD_<SERVICE>`, widen this to match (start period plus interval times retries, plus margin) |
| `XCHAIN_NODE_AUTOHEAL_STATE_DIR` | `~/.xchain-node` | Where the state file (`autoheal-state.json`) lives: last restart times, unhealthy onsets and the per-container restart count that drives the backoff. Falls back to `XCHAIN_NODE_LOCK_DIR` when that is set, otherwise `~/.xchain-node` |

## Telemetry

Expand Down
7 changes: 2 additions & 5 deletions bin/ci-full.sh
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,16 @@ fast_defer() {
# >>> ci-tier timer (generated block; re-run the tier wirer to update) >>>
run_tier() {
ci_tier_deferred "$1" && return 0 # ci-tier guard (generated)
if [ "${CI_TIER:-full}" = "fast" ] && [ -n "${FAILED:-}" ]; then echo; echo "ci:full ===== $1 NOT RUN (a push stops at its first red tier, its verdict already red; the full sweep runs it) ====="; return 0; fi # ci-tier stop (generated)
local name="$1"; shift
local __ci_tier_t0=$SECONDS
echo; echo "ci:full ===== $name ====="
local root
root="$(mktemp -d "${TMPDIR:-/tmp}/xchain-node-ci-full.XXXXXX")"
mkdir -p "$root/config" "$root/data"
if ( export XCHAIN_NODE_CONFIG_DIR="$root/config" XCHAIN_NODE_DATA_DIR="$root/data"; "$@" ); then
if "$@"; then
echo "ci:full ----- $name PASS ($(( SECONDS - __ci_tier_t0 ))s)"
else
FAILED="$FAILED [$name]"
echo "ci:full ----- $name FAIL ($(( SECONDS - __ci_tier_t0 ))s)"
fi
rm -rf -- "$root"
}
# <<< ci-tier timer <<<
need_sib() {
Expand Down
Loading
Loading