## The change

```ruby
class ReportsController < ApplicationController
  include RequireEntitlement
end
```

That is the whole gate. The concern adds a `before_action` that runs after authentication, so
`Current.account` is already set when it checks.

## Why the meaning lives somewhere else

`RequireEntitlement` deliberately does not know what entitlement is. It asks
`Entitlement.for(Current.account).entitled?` and acts on the answer. The definition is one line in
`app/models/entitlement.rb`:

```ruby
def for(account) = Subscription.new(account)
```

Point that at a different strategy and every gated controller changes at once. The file ships with a
paid subscription as the default and an `Open` strategy that gates nothing, which is what the
`remove-billing` skill switches to when an app turns out to be free. No controller is edited either
way.

## What the gate does not do

It answers one question: may this workspace use this surface at all. It says nothing about whether
this user may see this particular record. That is Pundit's job, and the two are orthogonal. A gated
controller still calls `authorize` and `policy_scope`, or a paying customer can read another paying
customer's rows.

## Check it both ways

A gate is only real if a spec proves the closed case:

```bash
bin/rspec spec/requests/projects_spec.rb
```

Two examples, minimum: an entitled account gets 200, an unentitled one is redirected. The example
`Project` slice has both, and it is the shape to copy.

## Entitlement reads never call Stripe

The check reads a local `Subscription` row that the webhook keeps in sync. That matters for latency
and for failure modes: a Stripe outage does not log out your paying customers, because nothing at
request time talks to Stripe at all.
