Background
A Substrate runtime upgrade with a storage migration has three hooks: pre_upgrade captures state, on_runtime_upgrade migrates, post_upgrade verifies. try-runtime runs them against a snapshot of real state before the upgrade is proposed.
What was found
During the September 2026 upgrade sequence, four post_upgrade hooks in EmpoorioChain's runtime were written as assertions about the world: this storage item is empty, this value is zero, no node is registered. They did not check what their own migration had done. Two failure modes follow:
- On a chain where the world is different — a testnet with accumulated state — the hook fails for reasons unrelated to the migration, blocking a correct upgrade.
- If the migration silently does nothing (wrong storage prefix, wrong version guard), a hook that checks the world rather than the effect passes anyway.
The rule
post_upgrade verifies the effect of its own migration and nothing else: compare against what pre_upgrade captured; assert that the old key is gone and the new key holds the transformed value; assert the storage version was bumped. It does not assert emptiness, zero, or absence of unrelated things.
All four hooks were rewritten to this form.
Why it belongs in a series about measurement
Because it is the same failure as a validator audit that cannot fail or a compliance check that is tautological: a verification that does not depend on the thing it claims to verify. The question the ecosystem now asks of every check — what would have to be true for this to fail? — applies to runtime hooks as much as to scripts.
Related
try-runtime remains mandatory before every migration, and it is what exposed these hooks: run against the live snapshot, the world-asserting hooks failed on state the migration had not touched.
From the runtime 213–220 upgrade sequence, September 2026.


