openapi: 3.1.0
info:
  title: Tenant Context Enforcement Contract
  version: 0.1.0
  description: >-
    Internal route and state contract for Spec 147. This feature does not introduce
    new public APIs; the contract documents the expected behavior of the existing
    workspace and tenant context routes plus the shared context-resolution object.
paths:
  /admin/choose-tenant:
    get:
      summary: Render the standard active-lane tenant selector
      operationId: showChooseTenant
      responses:
        '200':
          description: Choose-tenant page rendered for the current workspace
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChooseTenantSurfaceContract'
  /admin/select-tenant:
    post:
      summary: Persist active-lane tenant context for the current workspace
      operationId: selectTenantContext
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
                - tenant_id
              properties:
                tenant_id:
                  type: integer
      responses:
        '302':
          description: Tenant context accepted and redirect issued to the tenant-lane destination
        '404':
          description: Tenant missing, outside workspace, not entitled, or not eligible for standard active-lane selection
  /admin/clear-tenant-context:
    post:
      summary: Clear remembered tenant context for the current workspace
      operationId: clearTenantContext
      responses:
        '302':
          description: Tenant context cleared and redirect issued to a workspace-safe destination
  /admin/switch-workspace:
    post:
      summary: Switch the current workspace and re-evaluate tenant context
      operationId: switchWorkspace
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
                - workspace_id
              properties:
                workspace_id:
                  type: integer
      responses:
        '302':
          description: Workspace switched and tenant context cleared or re-evaluated for the new workspace
        '404':
          description: Workspace missing, archived, or actor is not a member
  /admin/tenants/{tenant}:
    get:
      summary: Resolve tenant-bound route subject independently from selected tenant context
      operationId: viewTenantRouteSubject
      parameters:
        - in: path
          name: tenant
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Authorized tenant-bound page renders from route subject authority
        '404':
          description: Tenant missing or actor not entitled to tenant scope
        '403':
          description: Actor is a tenant member but lacks a required capability for the page or action
  /admin/operations/{run}:
    get:
      summary: Resolve canonical workspace record viewer independently from selected tenant context
      operationId: viewCanonicalOperationRun
      parameters:
        - in: path
          name: run
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Authorized canonical run viewer renders even when selected tenant differs or is absent
        '404':
          description: Run missing, workspace membership missing, or tenant entitlement missing for a referenced tenant
        '403':
          description: Actor is otherwise in scope but lacks the required capability for the run type
components:
  schemas:
    ActiveSelectorOption:
      type: object
      additionalProperties: false
      required:
        - tenantId
        - workspaceId
        - lifecycle
        - isEligible
      properties:
        tenantId:
          type: integer
        workspaceId:
          type: integer
        lifecycle:
          type: string
          enum:
            - draft
            - onboarding
            - active
            - archived
        isEligible:
          type: boolean
          description: Must be true only for tenants eligible for standard active-lane selection.
        selectorLabel:
          type:
            - string
            - 'null'
    RememberedTenantContextState:
      type: object
      additionalProperties: false
      required:
        - workspaceId
        - status
      properties:
        workspaceId:
          type: integer
        tenantId:
          type:
            - integer
            - 'null'
        status:
          type: string
          enum:
            - no_selected_tenant
            - remembered_active
            - route_authoritative_tenant
            - stale_context_cleared
        invalidationReason:
          type:
            - string
            - 'null'
          enum:
            - workspace_mismatch
            - tenant_missing
            - tenant_not_entitled
            - tenant_not_selector_eligible
            - explicit_clear
            - null
    ChooseTenantSurfaceContract:
      type: object
      additionalProperties: false
      required:
        - workspaceId
        - selectorMeaning
        - options
      properties:
        workspaceId:
          type: integer
        selectorMeaning:
          type: string
          const: normal_active_operating_context
        options:
          type: array
          items:
            $ref: '#/components/schemas/ActiveSelectorOption'
        emptyStateBehavior:
          type: string
          enum:
            - no_active_tenants_available
            - workspace_selection_required
    RouteLegitimacyContract:
      type: object
      additionalProperties: false
      required:
        - routeType
        - authority
        - selectedTenantInfluence
      properties:
        routeType:
          type: string
          enum:
            - workspace_level
            - tenant_bound
            - canonical_workspace_record
        authority:
          type: string
          enum:
            - workspace
            - route_tenant
            - route_record
        selectedTenantInfluence:
          type: string
          enum:
            - none
            - informational_only
            - filter_only