* fix(pezkuwi): finish the Asset Hub cleanup and guard it against coming back
Three things left half-done, and a check so they stay done.
## Assets that were never created on chain
chains.json and v22/android/chains_minimal.json still declared Pezkuwi Asset Hub
assetIds 1001, 1002 and 1003 as DOT, ETH and BTC. Queried against
wss://asset-hub-rpc.pezkuwichain.io on 2026-08-11, assets.asset() returns None for all
three; only 1 (PEZ) and 1000 (wUSDT) are Live. They were added from a template — the
icons pointed at Nova's own repo — and shown to users, where any transfer would fail.
This is the second removal. The first, on branch fix/remove-nonexistent-asset-hub-assets
(2026-07-09), cleaned 66 files across v10-v22 but never touched these two, and was never
opened as a PR. A third branch, feature/asset-level-balance-test-fixture, went the other
way and added all three to a regression fixture. Both branches sat for a month.
## Assets served from a working branch
252 references under chains/ fetched icons from pending/post-fix-release. Every file
they named is byte-identical on master, main and that branch, so the dependency bought
nothing — and would have broken silently the day the branch was tidied away, which
nearly happened during this cleanup. Repointed to master, the branch the apps read.
## A fixture nothing keeps in step
sync_from_nova.py publishes chains, xcm, icons and config from the overlay, but never
tests/. So tests/pezkuwi_assets_for_testBalance.json and its overlay source are kept
aligned by hand. They agree today; nothing would have said so if they stopped.
Rather than invent a publish step whose conventions I would be guessing at, the drift
is now asserted.
## The check
scripts/check_pezkuwi_integrity.py, wired into the Code Quality job. Four assertions,
one per regression above, each carrying why it exists. Two of the four have already
recurred once, and the Nova sync will keep proposing the first one back — the current
sync branch (f6c3ebb9) reverts the isSufficient declaration, which is why the second
assertion exists.
Mutation-tested: restoring a ghost asset, removing isSufficient, repointing one icon at
a working branch, and nudging the fixture each fail it; reverting each passes.
* fix(overlay): declare sufficiency at the source, not in the generated output
The isSufficient declaration was added to chains/ — which sync_from_nova.py regenerates
from nova-base plus pezkuwi-overlay on every run. So the fix had a shelf life of exactly
one sync, and the sync branch already waiting (sync/nova-base-f6c3ebb9, 2026-08-08)
reverts it: its output carries {"assetId": "1000"} with no sufficiency, because it was
generated from an overlay that does not declare any.
Editing generated files is how this repo keeps losing the same change. The phantom
Asset Hub assets were removed twice and came back twice for the same reason.
Verified rather than assumed: added the field to
pezkuwi-overlay/chains/pezkuwi-chains.json, ran scripts/sync_from_nova.py, and all three
generated files — chains.json, v22/android/chains.json, v22/android/chains_minimal.json
— came out carrying isSufficient: true. git reported no change to any of them, meaning
the sync now produces exactly what the manual edit produced, so the two agree instead of
fighting.
The phantom assets do not return either: the overlay lists only HEZ, PEZ and USDT, so
regeneration drops 1001/1002/1003 by construction rather than by anybody remembering.
The hardcoded-secret scan flags any 64-hex 0x value in JSON as a possible
private key. The restored balance-test fixtures store public 32-byte
account IDs under "account" fields - public data by definition, tripping
the scan as a false positive. Scope the exclusion to the exact field name
rather than loosening the pattern itself.
The live Play Store release (wallet-android 85bde7e, published 2026-06-15)
was built against whatever was on this branch's HEAD at the time - which,
since master had received no commits between 2026-03-02 and this week, was
commit 7a087cf. This week's changes (nova-base sync, Tron config/icons,
balance test fixtures, etc.) are real and wanted, but they've made master
incompatible with that still-live app version, and live users installing
fresh right now get a completely empty tokens list because of it (the app's
chain sync silently fails whole-hog on any single malformed/incompatible
chain entry, leaving new installs with zero locally-cached chains).
This makes master's served content match 7a087cf exactly, stopping the
bleeding for current live users without needing an emergency app release.
None of this week's work is lost - it's all preserved on
pending/post-fix-release and will come back once wallet-android's Tron
send feature is complete and both repos can ship together in one
coordinated release.
auto-merge.yml only listened for the "Code Quality" workflow_run event.
Whenever "Security" (CodeQL etc., usually the slower of the two) finished
after Code Quality, the merge attempt fired too early, failed against the
still-pending required check, and nothing ever re-triggered it - the PR sat
open until someone noticed and merged it by hand. This is the actual cause
behind the recurring "master->main sync PR stuck" issue, not a one-off fluke.
Now listens for both workflows, and verifies every required check is
actually green (via `gh pr checks --required`) before merging rather than
trusting that the one workflow which fired us means everything is done -
whichever of the two finishes last will now successfully trigger the merge.
sync-nova-base.yml checked out and PR'd against whatever branch GitHub
considers the repo default - which is 'main', a read-only mirror kept in
sync FROM master (auto-pr.yml/auto-merge.yml only flow master -> main,
never the reverse). master is what the live app actually fetches configs
from (see wallet-android's CHAINS_URL etc. all pointing at .../master/...).
Net effect: every one of the 29 accumulated 'Sync from Nova Base' PRs
(#1 through #36, 2026-02-09 through 2026-07-09) landed on a branch nothing
downstream ever reads, so 5 months of upstream Nova chain/RPC/asset
maintenance never reached production regardless of whether those PRs got
merged. Explicit ref/base: master makes future runs target the branch that
actually matters; the 29 stale main-targeted PRs are being closed as
superseded now that #36's content has been applied to master directly (see
next commit).
master is where real development happens and gets pushed to directly
(main is the auto-synced mirror) - branch protection was just added to
master requiring these exact check contexts, but the workflows only
fired for PRs/pushes targeting main, so the required checks could never
actually run for a master PR, permanently blocking every future merge.
Every account_overrides.json/chains_for_testBalance.json entry has a
32-byte hex "account" field - a public AccountId32 (Substrate's public
account identifier), not a private key. The two share the same byte
length/hex format, but are fundamentally different: one is meant to be
public (it's literally how you address a chain account), the other
must stay secret. The scanner's regex can't tell them apart and flags
every single one, which just triggered a false "Possible private key
found" failure on PR #33 (the master->main sync).
This isn't a one-off - it'll fire on every future sync PR too, since
chains_for_testBalance.json always has these fields. Left as "FAILURE"
long-term, it trains reviewers to ignore this specific check, which is
exactly the alarm-fatigue failure mode that would let a real leaked
secret slip through unnoticed.
- Add sync_from_nova.py script to merge Nova chains with Pezkuwi overlay
- Add GitHub Action for daily auto-sync
- Sync all chains from nova-base (includes Polkadot Coretime and other missing chains)
- Pezkuwi chains appear first and take priority
This fixes DOT swap crash caused by missing Polkadot Coretime chain.