The predict(…) function gets called with UVM_PREDICT_WRITE or UVM_PREDICT_READ from inside a reg predictor. These calls are intended to model any side effects of accessing the registers. The post_predict(…) callback allows you to inject behavior (e.g. writing some register clears some bit in some other register, clearing some bit disables access to some other fields, etc.). If you want to model register updates caused by other events (e.g. some operation completing sets a flag), you call predict(…) with UVM_PREDICT_DIRECT. In that case you know exactly what value you want the register to contain and it makes little sense to step on your own toes inside a post_predict(…) callback.
Note: I’m not a UVM developer. This was purely my opinion. Whether the VIP TSC really had this in mind is a different question.