async def METHOD_NAME(
    request: ChangedRequest, specs_filter: SpecsFilter
) -> ChangedAddresses:
    no_dependents = request.dependents == DependentsOption.NONE
    owners = await Get(
        Owners,
        OwnersRequest(
            request.sources,
            # If `--changed-dependents` is used, we cannot eagerly filter out root targets. We
            # need to first find their dependents, and only then should we filter. See
            # https://github.com/pantsbuild/pants/issues/15544
            filter_by_global_options=no_dependents,
            # Changing a BUILD file might impact the targets it defines.
            match_if_owning_build_file_included_in_sources=True,
        ),
    )
    if no_dependents:
        return ChangedAddresses(owners)
    # See https://github.com/pantsbuild/pants/issues/15313. We filter out target generators because
    # they are not useful as aliases for their generated targets in the context of
    # `--changed-since`. Including them makes it look like all sibling targets from the same
    # target generator have also changed.
    #
    # However, we also must be careful to preserve if target generators are direct owners, which
    # happens when a generated file is deleted.
    owner_target_generators = FrozenOrderedSet(
        addr.maybe_convert_to_target_generator() for addr in owners if addr.is_generated_target
    )
    dependents = await Get(
        Dependents,
        DependentsRequest(
            owners,
            transitive=request.dependents == DependentsOption.TRANSITIVE,
            include_roots=False,
        ),
    )
    result = FrozenOrderedSet(owners) | (dependents - owner_target_generators)
    if specs_filter.is_specified:
        # Finally, we must now filter out the result to only include what matches our tags, as the
        # last step of https://github.com/pantsbuild/pants/issues/15544.
        #
        # Note that we use `UnexpandedTargets` rather than `Targets` or `FilteredTargets` so that
        # we preserve target generators.
        result_as_tgts = await Get(UnexpandedTargets, Addresses(result))
        result = FrozenOrderedSet(
            tgt.address for tgt in result_as_tgts if specs_filter.matches(tgt)
        )
    return ChangedAddresses(result)