This is related to #14150 and possibly others, but it's actually a separate issue.

For instance, when using the following query:
`bitcoin-cli scantxoutset start '[{"desc":"wpkh(xpubABCDEF/0/*)", "range":100}]'`
I can get a list of UTXOs, but no way to get back the index which derived that particular UTXO. So it's not much better than deriving on the user side and specifying addresses one by one, so that I already have a cache of addresses to match.

Not sure what the solution looks like. One way is to repeat the full descriptor in the utxo. That might get verbose though.
bool IsRange() const override { return m_provider->IsRange(); }
    bool IsSolvable() const override { return true; }
    std::string ToString() const override { return m_fn_name + "(" + m_provider->ToString() + ")"; }
    bool ToPrivateString(const SigningProvider& arg, std::string& out) const override
    {
        std::string ret;
        if (!m_provider->ToPrivateString(arg, ret)) return false;
        out = m_fn_name + "(" + std::move(ret) + ")";
        return true;
    }
    bool Expand(int pos, const SigningProvider& arg, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const override
    {
        CPubKey key;
        KeyOriginInfo info;
        if (!m_provider->GetPubKey(pos, arg, key, info)) return false;
        output_scripts = std::vector<CScript>{m_script_fn(key)};
        out.origins.emplace(key.GetID(), std::move(info));
        out.pubkeys.emplace(key.GetID(), key);
        return true;
    }
};
CScript P2PKHGetScript(const CPubKey& pubkey) { return GetScriptForDestination(pubkey.GetID()); }
CScript P2PKGetScript(const CPubKey& pubkey) { return GetScriptForRawPubKey(pubkey); }
CScript P2WPKHGetScript(const CPubKey& pubkey) { return GetScriptForDestination(WitnessV0KeyHash(pubkey.GetID())); }
class MultisigDescriptor : public Descriptor
{
    int m_threshold;
    std::vector<std::unique_ptr<PubkeyProvider>> m_providers;
public:
    MultisigDescriptor(int threshold, std::vector<std::unique_ptr<PubkeyProvider>> providers) : m_threshold(threshold), m_providers(std::move(providers)) {}