Yes, it seems to be a bug firstly because different output comes from different ways of specifying a Part
d = <|"a" -> <|"b" :> <|"c" -> <|"d" :> "e"|>|>|>|>;
d[["a", "b", All]] (* <|"c" -> <|"d" :> "e"|>|> *)
d[["a", "b", 1]] (* "c" -> <|"d" :> "e"|> *)
d[["a", "b", "c"]] (* Missing["KeyAbsent", "b"] *)
Mr Wizard's answer speculated that the cause of this might be due to when/how an Association is interpreted (or loses it atomicity) and while the above example tends to suggest otherwise, his reasoning might go some way to explaining the bug's origin. Certainly it appears as if some initial "whole processing" is taking place as (opposed the sequential d[["a"]][["b"]]) as the following analysis shows (and without being privy to the no-doubt many (competing) imperatives of Cases, Part, Query etc). Firstly, it seems to me that the example,
Cases["a" :> 3 I, _Complex] (* {} *)
(* anomalously IMO - {3 I} is more natural *)
should instead yield {3 I} (as should also Cases["a":>3 I, 3 I]) since it's more analogous to the second expression of the following as opposed to the fourth (since the number's Complex nature is a parsing issue more than an evaluative one).
Cases["b" -> 1, _Integer] (* {1} *)
Cases["b" :> 1, _Integer] (* {1} *)
t = 1;
Cases["b" -> 1, _Integer] (* {1} *)
Cases["b" :> t, _Integer] (* {} *)
Compare the last evaluation with
Cases["a" :> 3 I, _?NumberQ] (* {3 I} *)
Cases["b" :> t, _?IntegerQ] (* {1} *)
which are both expected since now each part gets evaluated in the test. Hence Cases respects the evaluation instruction in ->, :> while looking at an expression's structure only overiding this when explicitly asked to do so (such as in a test). Similarly, Part respects ->, :> evaluation instruction when looking at an Association's structure
t = <|"b" -> 1|>;
D1 = <|"a" -> t|>;
D2 = <|"a" :> t|>;
D1[["a", "b"]] (* 1 *)
D2[["a", "b"]] (* Missing["KeyAbsent","a"] *)
Query however, will overide :>'s delayed-evaluation to avoid not finding anything
D1 // Query["a", "b"] (* 1 *)
D2 // Query["a", "b"] (* 1 *)
Sometimes this can lead to apparently anomalous, but probably, ultimately useful behaviour
s[2] = <|"b" -> 1, "c" -> 3|>;
D3 = <|"a" -> s[2]|>;
D4 = <|"a" :> s[2]|>;
D3[["a", 1]] (* 1 *)
D3[["a", 2]] (* 3 *)
D4[["a", 1]] (* 2 *)
D4[["a", 2]] (* Missing["KeyAbsent","a"] *)
D4 // Query["a", 1] (* 2 *) (* not 1 as might be expected as per below *)
D4 // Query["a", 2] (* 3 *) (* apparently anomalous but probably useful *)
When it comes to more deeply nested associations, Part allows this :> evaluative instruction to (IMO anomalously) obscure the initial structure provided
D5 = <|"a" -> <|"b" -> 1|>|>;
D6 = <|"a" :> <|"b" -> 1|>|>;
D5[["a", "b"]] (* 1 *)
D6[["a", "b"]] (* Missing["KeyAbsent","a"] *) (* anomolously IMO - 1 is more natural *)
unlike Query which as per its usual earnest self invariably pulls out all stops (or at least parts)
D5 // Query["a", "b"] (* 1 *)
D6 // Query["a", "b"] (* 1 *)
In other words, to remove these claimed anomalies with deeply nested Associations, two Associations that are identical modulo Rule, RuleDelayed (both in unevaluated an evaluated forms) need to have the same output when Part operates on them - an eventuality guaranteed with Unit Tests satisfing this condition doubling up with Rules replaced with RuleDelayeds.
N.B. The other observed behaviour/formatting anomalies seem more clearcut
{"a" -> 1} // Query["a"] (* 1 *)
{"a" :> 1} // Query["a"] (* Missing["PartInvalid", "a"] *)
<|"a" -> <|"b" -> 1|>|> (* <|"a" -> <|"b" -> 1|>|> *)
<|"a" :> <|"b" -> 1|>|> (* <|"a" :> Association["b" -> 1]|> *)