Very good question, even harder to explain. I think it's the best to show it along the lines of one test case to be found in `test_accept_and_content_type`.

service definition:

    # test a mix of "accept" and "content_type" parameters
    service7 = Service(name="service7", path="/service7")
    @service7.post(accept='text/xml', content_type='application/json')
    def handler(request):
        pass

test:

    response = app.post('/service7',
        headers={
            'Accept': 'text/plain, application/json',
            'Content-Type': 'application/json; charset=utf-8'}, status=406)

Well, the alternative to "establish predicates through computing the cartesian product of possible predicate combinations" would be by adding them sequentially: First views with `accept` predicates **only** by looping through all `accept` service parameters, then views with `content_type` predicates **only** by looping through all `content_type` service parameters.

In this case, the test case above would croak with `AppError: Bad response: 200 OK (not 406)`.

Rationale: Even if there's an obvious mismatch on the `accept` constraint (service provides only `text/xml` responses, while client asks for `text/plain, application/json`), Pyramids request predicate system dispatches the request as "successful" for obvious reasons as well: The content type constraint for the request body matches and this very view registration has no other constraints attached... :-(

So we must never register views with one predicate kind lacking the other predicate kind if the service is annotated with both kinds of predicates. Computing the cartesian product of both lists was the self-evident solution for me, although the insight was really painful at first. As a bonus, this would scale out in a generic way when passing through more kinds of predicates in the future.

Cheers!