Organization-level Runner (Admission) Controller
## Overview
Implement organization-level Runner (Admission) Controllers, extending the existing instance-level implementation ([&19660](https://gitlab.com/groups/gitlab-org/-/work_items/19660)) to support organizations as a first-class entity. This enables organizations to manage their own runner controllers independently, with full cell-awareness for GitLab Cells architecture.
## Background
Instance-level runner controllers were implemented in [&19660](https://gitlab.com/groups/gitlab-org/-/work_items/19660) with:
- `ci_runner_controllers` and `ci_runner_controller_tokens` tables in `gitlab_ci_cell_local` schema
- Instance-level and runner-level scopings
- External REST API, internal Job Router API, audit events, PDI events, CLI commands, and client-go support
Organization-level runner controllers extend this model to the `gitlab_ci` schema (sharded by `organization_id`), enabling multi-tenant runner admission control that is cell-aware and routable.
## Key Design Principles
1. **Cell-aware**: All models live in `gitlab_ci` schema sharded by `organization_id`. Tokens must be routable via the HTTP Router with organization-encoded prefixes.
2. **Mirrors instance-level patterns**: Follows the same controller → token → scoping model established in Phase 1, adapted for organization ownership.
3. **Scoping hierarchy**: Organization-level controllers support scoping at:
- **Organization level** — applies to all groups/projects in the organization
- **Organization runner level** — applies to specific organization-owned runners
- **Group level** — applies to all projects within a group
- **Project level** — applies to jobs in a specific project
- **Group runner level** — applies to specific group-type runners
- **Project runner level** — applies to specific project-type runners
4. **Downward application**: Scopes always apply "downward" in the hierarchy.
## Database Schema
```mermaid
graph TD
subgraph org_scoped["gitlab_ci — shard: organization_id"]
org_ci_runner_controllers["org_ci_runner_controllers"]
org_ci_runner_controller_tokens["org_ci_runner_controller_tokens"]
org_ci_runner_controller_org_level_scopings["org_ci_runner_controller_org_level_scopings"]
org_ci_runner_controller_runner_level_scopings_org_type["org_ci_runner_controller_runner_level_scopings<br/>(organization runners)"]
org_ci_runner_controller_runner_level_scopings_group_type["org_ci_runner_controller_runner_level_scopings<br/>(group runners)"]
org_ci_runner_controller_runner_level_scopings_project_type["org_ci_runner_controller_runner_level_scopings<br/>(project runners)"]
org_ci_runner_controller_scopings_group["org_ci_runner_controller_scopings_group"]
org_ci_runner_controller_scopings_project["org_ci_runner_controller_scopings_project"]
group_type_ci_runners["group_type_ci_runners<br/>(existing)"]
project_type_ci_runners["project_type_ci_runners<br/>(existing)"]
org_ci_runner_controllers -->|has_many| org_ci_runner_controller_tokens
org_ci_runner_controllers -->|has_one| org_ci_runner_controller_org_level_scopings
org_ci_runner_controllers -->|has_many| org_ci_runner_controller_runner_level_scopings_org_type
org_ci_runner_controllers -->|has_many| org_ci_runner_controller_runner_level_scopings_group_type
org_ci_runner_controllers -->|has_many| org_ci_runner_controller_runner_level_scopings_project_type
org_ci_runner_controllers -->|has_many| org_ci_runner_controller_scopings_group
org_ci_runner_controllers -->|has_many| org_ci_runner_controller_scopings_project
org_ci_runner_controller_runner_level_scopings_group_type -->|FK: runner_id| group_type_ci_runners
org_ci_runner_controller_runner_level_scopings_project_type -->|FK: runner_id| project_type_ci_runners
end
style org_scoped fill:#0d1117,stroke:#a78bfa,stroke-width:2px
```
epic