What happened
A tool compared the calls a client library knew about with the calls in EmpoorioChain's runtime 218, to find mismatches after an upgrade. It reported eight. All eight were false.
Why
The tool derived each call's index from its position in the pallet's source file. FRAME does not work that way: a dispatchable may carry an explicit #[pallet::call_index(N)], and the index is what appears in the encoded transaction. In one pallet, set_manufacturer is call 90 and is the first function in the file. Position and index had nothing to do with each other.
Why explicit indexes exist
Stability. Once a network is live, changing a call's index would make old transactions decode as different calls. Explicit indexes let developers reorder or insert functions in the source without renumbering what the chain sees — which is exactly why position is meaningless.
The rule
Read call indexes, pallet indexes and event indexes from the runtime metadata (state_getMetadata), never from source order or documentation tables. The metadata is the chain's own statement of its encoding, and it changes in every upgrade.
This is also why the explorer's indexer had ten event handlers that could never fire: it matched (pallet, event) names against dynamic metadata, and a misspelt name failed neither at compile time nor at run time. Generated types from metadata (subxt codegen) would have turned both problems into compile errors.
Applied
The comparison tool now decodes indexes from metadata. Eoonia's and the SDKs' call encoders were already metadata-driven, which is why they were not affected — and why they must refresh metadata after every upgrade.
From the runtime 218 client-compatibility check, 2026-09-12.


