Take my opinion with a grain of salt: I have no experience with protos in Chrome OS, but plenty of experience in other orgs.
In an ideal world one would be able to delete+reserve fields the moment they are no longer needed, and often in self-contained situations that is possible. I would agree this is the preferred option if it is possible - no reason to have fields sitting around that aren't used or useful. But sometimes that's not feasible to do that, particularly when you don't have tight and absolute control over updates, so I think the suggested fallback of setting deprecated=true would work better than not marking it deprecated in most cases.
For an example of when it's infeasible to delete+reserve immediately, say there is a message type X which has a field 'a' that is being set already in some code (the "writer") that already is launched and already is recording messages of type X regularly; let's also assume that somewhere else I have another program (the "reader") which is reading this 'a' field and doing some stuff with it, and then discards the rest of the X message. If I want to change the "writer" code to instead write to a new field 'b', I can't just delete+reserve the field 'a' at the same time: even if I could easily remove all references to 'a' in the "writer" code in one fell swoop, I still want to be able to read all of the data any existing "writer"s are writing until all of those binaries are updated with the newer version which writes field 'b'. This necessitates leaving both fields in the proto at the same time, but (assuming the intent is to fully migrate from field 'a' to 'b') it seems like the 'a' field could be marked deprecated to help avoid people adding new dependencies on it. Unfortunately, depending on the release cycle of the "writer", the field may have to be deprecated for many months or perhaps indefinitely. I don't love the idea of having a deprecated field that is intentionally going to be left there for a long time, but it seems better than any of the alternatives...
Even for slightly more controlled situations where you do fully control the update cycle for readers/writers of some proto, it can still be tricky to do a total migration all at once. As another example, storing proto messages persistently can cause a similar problem as before. If you want to move from Y.j to Y.k, but you're storing messages of type Y on/in a disk/database, then I see three options: 1) accept you've lost all historical data in field 'j'; 2) write some wrapping logic to encapsulate the Y message, allowing for code to use a single API to access either 'j' or 'k' automatically; 3) write a backfill program which mechanically changes 'j' to 'k' in the persistent storage. Option #1 allows you to delete+reserve immediately; for option #2 you have to leave the field in the message indefinitely; option #3 is similar to the above example, where you can eventually delete+reserve the field but both have to exist in the proto message at some point in order for the backfill code to be checked in; in this case setting the old field to deprecated makes sense, assuming the backfill is going to happen ~soon. Option #2 may sound like a bad idea on first consideration, but presuming sufficient encapsulation in the wrapper type I've seen this work out fine in some large projects. It really depends on the circumstance and how complicated the wrapper type needs to be. But this is the case it's not clear to me whether marking the old field as deprecated is right: it somewhat depends on the situation, e.g. who is setting fields of that proto, a client on its own or is it being set via the wrapper type.