First, even if you find the transaction with the lowest effective fee rate in a block, that will not necessarily mean that the mempool cleared to that level. In their recent paper "On Blockchain Commit Times: An analysis of how miners choose Bitcoin transactions", Messias et al observe deviations in the block composition from the expected norm (GetBlockTemplate) of up to 22%. They surmise that this could be caused by out-of-band prioritization or use of other algorithms.
Fact is, we don't know what software miners are running to compose blocks, how often they update their templates, how often they get acceleration requests or have their own interests to include transactions, and which version of Bitcoin Core they may be running if they even they simply use GetBlockTemplate (GBT).
Assuming that blocks are generally produced by Bitcoin Core's GetBlockTemplate method, and applying general rules for block composition, we know the following:
- Transactions must be ordered topologically in a block
If a transaction spends UTXOs created within the
same block, the child transaction must follow the parent in the block's transaction list
- GBT selects in order of effective fee rate
- GBT will select complete transaction ancestor groups
This means either a single transaction if no child transaction is present, or the descendants have a lower effective feerate, or the complete group derived from the descendant that has the highest effective feerate.
- Groups may be skipped when they don't fit in the block
If a transaction group requires more blockspace than is left, a smaller transaction group with a lower effective feerate will get included instead. This means that larger transaction groups may miss a block even though transactions with lower feerates made it in.
- Only the best sibling counts
Sibling transactions do not form a shared ancestor group unless the
ancestor group is started from a shared descendant. I.e. if two siblings both have higher feerates than the parent, they each form a separate ancestor group in the candidate list and get prioritized on basis of the effective feerate of their individual group. When the ancestor group with the higher effective feerate gets selected, all remaining ancestor groups get recalculated and the sibling transactions would now likely have the highest effective feerate right afterwards (since it was higher than the parent alone). So, even if siblings and parents all appeared grouped in a block, they would be positioned at the highest effective feerate among the individual ancestor groups, the parent does not gain a special benefit from being CPFPed multiple times in parallel, and they were actually selected iteratively not together.
Altogether, it would be expected that transactions should appear in descending order of their feerate in the block (when using GBT), except where topology interferes, or transactions have been imbued with a "virtual high-feerate" via PrioritiseTransaction. I.e. you could look at the effective feerates of the last few transactions in the block and make a guess from there. Taking a low percentile instead may give you a more representative value.