After https://secure.phabricator.com/D20726 (Aug 21), when a custom field is “required” but also “disabled” by a subtype, the “disabled” behavior is now stronger, and the field will be completely disabled for tasks of that subtype. This might solve your problem if your goal is to have a field which appears and is required on subtype X and does not appear on other subtypes, and you’re running into the not-exactly-a-bug-but-not-a-very-helpful-behavior (from prior to Aug 21) where “required” was stronger and you’d end up with a field that was required but which you could not edit.
If you want a field which appears on multiple subtypes (say, X, Y, Z) but is required on only some of them (say, X), this will be supported in the future by changes connected to https://secure.phabricator.com/T13248, which will let you override more field behavior on a subtype-by-subtype basis. There’s recent customer interest in this but it hasn’t really made it into the development pipeline yet so I have no real guesses on timeline, but at least more of a “future change” than a “far future change”.
The Herald approach isn’t ideal. Herald can’t prevent edits from taking place; it can only react to edits. This is a less user-friendly than actually preventing the edit, and might make a few other things more complicated (for example, webhooks would see tasks rapidly swapping between invalid and valid states, since both edits really occurred from Phabricator’s point of view, and might need to be updated to understand that this kind of edit “doesn’t count”). However, this is broadly reasonable as a stopgap and there’s no reason it can’t work well enough to be worth doing, just a lot of little ways it’s an imperfect approach.
The upstream blocker for this today is actually just that it’s not obvious what conditions we should provide for field types like “number” and “date”, upstream in https://secure.phabricator.com/T13039. Of the two, “number” is probably trickier. Various use cases have arisen where numeric fields may want a hugely wide variety of tests (exists, greater than X, in range X-Y, belongs to some specific set of numbers, is a fibonacci number, has remainder R when divided by Q, etc).
We could imagine some similar set of fairly complex use cases might exist for dates (“is a workday”, “is a monday”, etc).
None of these are especially hard to implement, but the use cases to date are generally weak enough that building this support is hard to motivate. In most cases, using Herald to test numeric and date fields solves some problem which would be better solved with some other change (including here, where selective-requirement-per-subtype is a better fix than date-requirement-via-Herald).