For an SPF check to pass, the sending IP address must pass at least one of the mechanisms. Include mechanisms test the incoming IP address using the included SPF record and 'return' the result.
Using your example:
a.example.com IN TXT "v=spf1 include:b.example.com +all"
b.example.com IN TXT "v=spf1 -all"
The included record will return fail, since it only contains a -all mechanism. However, the first record will pass because it has a +all mechanism.
Using a more detailed example:
a.example.com IN TXT "v=spf1 ip4:1.2.3.4 mx include:spf.example.org -all"
a.example.com IN MX 0 mailserver.example.com
mailserver.example.com IN A 1.2.3.5
spf.example.org IN TXT "v=spf1 ip4:4.3.0.0/16 -all"
I will write down the result of each mechanism in the same order they are specified in the record. So, the results will be formatted as such:
- a.example.com:
[ip4] [mx] [include] [-all]
- spf.example.org:
[ip4] [-all]
With the following sender addresses:
1.2.3.4
- spf.example.org ->
fail fail
- a.example.com ->
pass fail fail fail
The final result will be pass, since at least one check passed
1.2.3.5
- spf.example.org ->
fail fail
- a.example.com ->
fail pass fail fail
The final result will be pass, since at least one check passed
4.3.10.20
- spf.example.org ->
pass fail
- a.example.com ->
fail fail pass fail
The final result will be pass, since at least one check passed
TL;DR: The include mechanism is evaluated separately and the result passed back to the evaluation of the record that included it. Record evaluation fails if no mechanisms match. Since you ended your example with +all, it will always match and therefore pass.