I think the biggest problem that I introduced was not using real code - I attempted to continue using the objects you created. I'm showing application code below which I hope will make the case clear. I'll address these out of order:

> Aside from all of this, we could have just created a policy for the join model instead

For our application the API that we developed backgrounded the fact that there is a join model. We actually wrote two separate implementations, the one we decided to go with and one that brought the join model to the foreground (significantly more code and less clear intent). Our current API looks like:

``` ruby
# tug(master)$ cat app/models/project.rb 
class Project < ActiveRecord::Base
  has_many :collaborations, dependent: :destroy

  # Add the user to the project and transfer project ownership if they are the
  # only collaborator. If the user already belongs to the project, this method
  # does nothing.
  #
  # @return [User] User that was added.
  def add_user user
    if users.empty?
      users << user
      transfer_ownership_to_user user
    else
      users << user unless users.include? user
    end

    user
  end

  # Removes the user from the project by destroying the collaboration.
  #
  # @note After the collaboration has been removed the in memory collaborators
  #   is not updated. An explicit call to reload seems to be the only way to
  #   force an update.
  # @param user [User] User to be removed.
  # @return [User] User that was removed.
  def remove_user user
    raise NotCollaboratingError unless users.include?(user)

    collaborations.remove_user_belonging_to_project user, self
    reload
    user
  end

  # Transfers project ownership from an existing user to another user.
  #
  # @param user [User] User to become project owner.
  # @return [User] User that has received project ownership.
  def transfer_ownership_to_user user
    raise NotCollaboratingError unless users.include?(user)

    collaborations.transfer_ownership_of_project_to_user user, self
    user
  end
end

# tug(master)$ cat app/views/projects/collaborators.html.erb 
<ul class="list-group">
  <% project.users.each do |user| %>
    <li class="list-group-item media pinboard">
        <% if policy(project).remove_user?(user) %>
          <%= link_to 'Remove', project_collaborator_path(project, user), method: 'delete', class: 'btn btn-danger btn-small pin-right', style: 'top: 20px; right: 15px' %>
        <% end %>
      </div>
    </li>
  <% end %>
</ul>
```

From these snippets you can see that we don't have access to the collaboration at this point, nor is there really a requirement to. In fact adding it would make this code a lot less readable IMO. I'm happy to understand how you would have approached this differently.

> This example is weak.

Fair point. I wanted to write documentation that was consistent with the objects that you'd constructed. My implementation for `policy(project).remove_user?(user)` shown above:

``` ruby
# tug(master)$ cat app/policies/project_policy.rb 
class ProjectPolicy < ApplicationPolicy
  # Determine if the user has permission to remove the specified user.
  #
  # @return [Boolean]
  def remove_user? other_user
    user != other_user && project_owned_by_user?
  end

  private

  def project_owned_by_user?
    record.owned_by? user
  end
end
```

I believe this policy method cleanly fits inside your description of <q>Authorization should be solely for the purpose of who is allowed to do what</q>. I can't think of another way to write this - again I'd be happy to be shown a better / different implementation.