See discussion in T4189.
I think I'm going to do this in two hook phases. The first phase is the "ref" phase and controls adding, changing, and removing tags, branches and bookmarks. The fields would be things like:
[New tags] [exist] [Modified branches] [include] [master] [Modified branches] [match regexp] [/whatever/] [Deleted bookmarks] [include] [quack] [Repository] [is] [rP] [Pusher] [is] [alincoln]
The only action is "reject with message":
[Reject with message] ["Interns aren't allowed to touch master."]
This phase can't examine commit content, but can encode a bunch of rules like who can push to master, who can create or delete tags or branches, etc. This phase doesn't fire in Subversion, since there are no meaningful ref-like metadata artifacts.
The second phase is the "commit" phase and looks very similar to the existing commit hooks. It has fields like:
[Commit message] ... [Affected files] ... [Author] ...
...etc. It will have a few new special rules, like:
[Committer] [Commit is new branch head?] [Commit is merge?] [Commit branches]
This permits all the content-based rules to fire.
I think this will cover the vast majority of cases. One issue is that putting all of this in Herald global rules means you may automatically have rules apply to repositories you create and be unable to edit them (e.g., if all users can create repositories but only admins can manage global rules). But this is good in the common case where you have multiple similar repositories, and I think we can wait and see if it's a problem in practice. Additional changes in the future (like tagging repositories with projects) should make it easier to write rules that don't step on anyone's toes, even for larger organizations.