RSpec on the backend, exhaustively covering every role against every permission; static analysis (ESLint + strict TypeScript) as the frontend's quality gate.

# spec/policies/event_policy_spec.rb

require "rails_helper"

RSpec.describe EventPolicy, type: :policy do
  let!(:lead)        { create(:amigo) }
  let!(:assistant)   { create(:amigo) }
  let!(:participant) { create(:amigo) }
  let!(:outsider)    { create(:amigo) }
  let!(:admin)       { create(:amigo, role: :admin) }

  let!(:event) { create(:event, lead_coordinator: lead) }

  before do
    create(:event_amigo_connector, :lead, event: event, amigo: lead)
    create(:event_amigo_connector, :assistant, event: event, amigo: assistant)
    create(:event_amigo_connector, :participant, event: event, amigo: participant)
  end

  def policy_for(user, record = event)
    described_class.new(user, record)
  end

  describe "top-level permissions" do
    it "update? is allowed for admin, lead, or assistant" do
      expect(policy_for(admin).update?).to eq(true)
      expect(policy_for(lead).update?).to eq(true)
      expect(policy_for(assistant).update?).to eq(true)

      expect(policy_for(participant).update?).to eq(false)
      expect(policy_for(outsider).update?).to eq(false)
      expect(policy_for(nil).update?).to eq(false)
    end

    it "destroy? is allowed for admin or lead only" do
      expect(policy_for(admin).destroy?).to eq(true)
      expect(policy_for(lead).destroy?).to eq(true)

      expect(policy_for(assistant).destroy?).to eq(false)
      expect(policy_for(participant).destroy?).to eq(false)
      expect(policy_for(outsider).destroy?).to eq(false)
    end
  end

  describe "role management" do
    it "manage_roles? is allowed for admin or lead only (not assistant)" do
      expect(policy_for(admin).manage_roles?).to eq(true)
      expect(policy_for(lead).manage_roles?).to eq(true)
      expect(policy_for(assistant).manage_roles?).to eq(false)
    end
  end

  describe "nil record safety" do
    it "does not require a record for create? (record may be nil on create checks)" do
      expect(described_class.new(outsider, nil).create?).to eq(true)
      expect(described_class.new(nil, nil).create?).to eq(false)
    end
  end
end

Every predicate gets checked against admin / lead / assistant / participant / outsider / nil — including the edge case of authorizing a not-yet-created record.

The frontend has no automated test suite yet — its npm test script runs eslint + a strict tsc --noEmit typecheck (package.json) rather than unit tests.