As part of #97030, some interesting behaviour surfaced about the terminate_after functionality: there are situations in which the actual collection early terminates (throws `CollectionTerminatedException`), both in the case where only top docs are collected as well as when aggs and top docs are collected. In this scenario, if `terminate_after` was provided in the search request, we keep on collecting documents, with the only purpose of counting and setting `early_terminated` to true once the threshold is reached.  

This may be perceived as a change in behaviour, because there are cases where we will not return `early_terminated` set to `true` while we previously would. In reality, we should clarify expectations and perhaps update the docs to indicate that `terminate_after` will terminate the actual collection of documents, but there are situations in which the collection either does not happen (because doc count is retrieved from the index statistics through `Weight#count`) or early terminates in which `terminate_after` cannot be honoured. This is fine, as the purpose of the functionality is to stop doing work early, and we should not cause additional work (the needless counting) to honour the functionality.

There are 5 TODOs in different places where `CollectionTerminatedException` is thrown in `QueryPhaseCollector`, that begin with:

> // TODO we keep on collecting although we have nothing to collect

The goal of this issue is to remove those TODOs and adjust the code to unconditionally rethrow `CollectionTerminatedException` when the collection has terminated. In the case of top docs collection without aggs, this should lead to a further simplification around removing null checks for the underlying leaf collector. There are some tests that will fail in `QueryPhaseTests` which need to have their expectations adjusted.
server/src/test/java/org/elasticsearch/search/query/QueryPhaseTests.java
QueryPhase.addCollectorsAndSearch(context);
            assertEquals(numDocs, context.queryResult().topDocs().topDocs.totalHits.value);
            assertEquals(TotalHits.Relation.EQUAL_TO, context.queryResult().topDocs().topDocs.totalHits.relation);
        }
        {
            
            
            TestSearchContext context = createContext(newContextSearcher(reader), new MatchAllDocsQuery());
            context.setSize(0);
            context.parsedPostFilter(new ParsedQuery(new MatchNoDocsQuery()));
            QueryPhase.executeQuery(context);
            assertEquals(0, context.queryResult().topDocs().topDocs.totalHits.value);
            assertEquals(TotalHits.Relation.EQUAL_TO, context.queryResult().topDocs().topDocs.totalHits.relation);
        }
        {
            
            TestSearchContext context = createContext(newContextSearcher(reader), new MatchAllDocsQuery());
            context.setSize(10);
            context.parsedPostFilter(new ParsedQuery(new MatchNoDocsQuery()));
            QueryPhase.addCollectorsAndSearch(context);
            assertEquals(0, context.queryResult().topDocs().topDocs.totalHits.value);
            assertEquals(TotalHits.Relation.EQUAL_TO, context.queryResult().topDocs().topDocs.totalHits.relation);
        }
    }
    public void testTerminateAfterWithFilter() throws Exception {
        indexDocs();
        TestSearchContext context = createContext(newContextSearcher(reader), new MatchAllDocsQuery());
        context.terminateAfter(1);
        context.setSize(10);
        context.parsedPostFilter(new ParsedQuery(new TermQuery(new Term("foo", "bar"))));