def METHOD_NAME(original: Changable,
                    new: Changable,
                    base_prefix: Offset = ()
                    ) -> List[Change]:
    """
    Return a list of `changed fields` between two dict structures.
    A `changed field` is represented by a 3-tuple made up of:
    1. `offset` to the change - a tuple of `item` accessors on the document.
    2. What is in `original` - Either a single value, a dict or list, or :data:`MISSING`.
    3. What is in `new`
    If the documents are identical, an empty list is returned.
    :type original: Union[dict, list, int]
    :rtype: list[(tuple, object, object)]
    """
    changed_fields: List[Change] = []
    if original == new:
        return changed_fields
    if isinstance(original, dict) and isinstance(new, dict):
        all_keys = set(original.keys()).union(new.keys())
        for key in all_keys:
            changed_fields.extend(METHOD_NAME(original.get(key, MISSING),
                                                  new.get(key, MISSING),
                                                  base_prefix + (key,)))
    elif isinstance(original, list) and isinstance(new, list):
        for idx, (orig_item, new_item) in enumerate(zip_longest(original, new)):
            changed_fields.extend(METHOD_NAME(orig_item, new_item, base_prefix + (idx, )))
    elif isinstance(original, tuple) or isinstance(new, tuple):
        if not numpy.array_equal(cast(Sequence[Any], original), cast(Sequence[Any], new)):
            changed_fields.append((base_prefix, original, new))
    else:
        changed_fields.append((base_prefix, original, new))
    return sorted(changed_fields, key=lambda a: a[0])