openapi: 3.1.0
info:
  title: Workspace Baseline Compare Matrix Internal Surface Contract
  version: 0.1.0
  summary: Internal logical contract for workspace baseline compare matrix reads, drilldown context, and compare-all launch behavior
  description: |
    This contract is an internal planning artifact for Spec 190. The affected routes still
    render HTML through Filament and Livewire. The schemas below define the bounded read
    models and action payloads that must be derivable from existing baseline, compare,
    finding, and run truth before the matrix surface can render or trigger compare-all.
servers:
  - url: /internal
x-baseline-compare-matrix-consumers:
  - surface: baseline.profile.detail
    sourceFiles:
      - apps/platform/app/Filament/Resources/BaselineProfileResource/Pages/ViewBaselineProfile.php
    mustRender:
      - baseline_profile_id
      - reference_snapshot_id
      - visible_tenant_count
      - open_compare_matrix_action
      - compare_assigned_tenants_action
  - surface: baseline.compare.matrix
    sourceFiles:
      - apps/platform/app/Filament/Pages/BaselineCompareMatrix.php
      - apps/platform/resources/views/filament/pages/baseline-compare-matrix.blade.php
    mustRender:
      - reference
      - filters
      - tenant_summaries
      - subject_summaries
      - matrix_rows
      - freshness_legend
      - trust_legend
    mustAccept:
      - policy_type
      - state
      - severity
      - tenant_sort
      - subject_sort
      - subject_key
  - surface: tenant.compare.drilldown
    sourceFiles:
      - apps/platform/app/Filament/Pages/BaselineCompareLanding.php
      - apps/platform/app/Support/Navigation/CanonicalNavigationContext.php
    mustRender:
      - matrix_source_context
      - baseline_profile_id
      - subject_key
      - back_link
paths:
  /admin/baseline-profiles/{profile}/compare-matrix:
    get:
      summary: Render the workspace baseline compare matrix for one selected baseline profile
      operationId: viewBaselineCompareMatrix
      parameters:
        - name: profile
          in: path
          required: true
          schema:
            type: integer
        - name: policy_type
          in: query
          required: false
          schema:
            type: array
            items:
              type: string
        - name: state
          in: query
          required: false
          schema:
            type: array
            items:
              $ref: '#/components/schemas/MatrixCellState'
        - name: severity
          in: query
          required: false
          schema:
            type: array
            items:
              $ref: '#/components/schemas/FindingSeverity'
        - name: tenant_sort
          in: query
          required: false
          schema:
            $ref: '#/components/schemas/TenantSort'
        - name: subject_sort
          in: query
          required: false
          schema:
            $ref: '#/components/schemas/SubjectSort'
        - name: subject_key
          in: query
          required: false
          schema:
            type: string
          description: Optional focused subject row selector for subject-first drilldown within the same matrix route.
      responses:
        '200':
          description: Rendered workspace matrix plus a fully derived matrix bundle
          content:
            text/html:
              schema:
                type: string
            application/vnd.tenantpilot.baseline-compare-matrix+json:
              schema:
                $ref: '#/components/schemas/BaselineCompareMatrixBundle'
        '403':
          description: Actor is in scope but lacks workspace baseline view capability
        '404':
          description: Workspace or baseline profile is outside actor scope
  /internal/workspaces/{workspace}/baseline-profiles/{profile}/compare-assigned-tenants:
    post:
      summary: Launch compare for all visible assigned tenants under the selected baseline profile
      operationId: compareAssignedTenants
      parameters:
        - name: workspace
          in: path
          required: true
          schema:
            type: integer
        - name: profile
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Compare-all launch summary derived from underlying tenant compare starts
          content:
            application/vnd.tenantpilot.compare-assigned-tenants+json:
              schema:
                $ref: '#/components/schemas/CompareAssignedTenantsLaunchResult'
        '403':
          description: Actor is in scope but lacks workspace baseline manage capability
        '404':
          description: Workspace or baseline profile is outside actor scope
components:
  schemas:
    MatrixCellState:
      type: string
      enum:
        - match
        - differ
        - missing
        - ambiguous
        - not_compared
        - stale_result
    FindingSeverity:
      type: string
      enum:
        - low
        - medium
        - high
        - critical
    FreshnessState:
      type: string
      enum:
        - fresh
        - stale
        - never_compared
        - unknown
    TrustLevel:
      type: string
      enum:
        - trustworthy
        - limited_confidence
        - diagnostic_only
        - unusable
    TenantSort:
      type: string
      enum:
        - tenant_name
        - deviation_count
        - freshness_urgency
    SubjectSort:
      type: string
      enum:
        - deviation_breadth
        - policy_type
        - display_name
    MatrixReference:
      type: object
      additionalProperties: false
      required:
        - workspaceId
        - baselineProfileId
        - baselineProfileName
        - baselineStatus
        - referenceState
        - assignedTenantCount
        - visibleTenantCount
      properties:
        workspaceId:
          type: integer
        baselineProfileId:
          type: integer
        baselineProfileName:
          type: string
        baselineStatus:
          type: string
        referenceSnapshotId:
          type:
            - integer
            - 'null'
        referenceSnapshotCapturedAt:
          type:
            - string
            - 'null'
          format: date-time
        referenceState:
          type: string
        referenceReasonCode:
          type:
            - string
            - 'null'
        assignedTenantCount:
          type: integer
        visibleTenantCount:
          type: integer
    MatrixTenantSummary:
      type: object
      additionalProperties: false
      required:
        - tenantId
        - tenantName
        - freshnessState
        - matchedCount
        - differingCount
        - missingCount
        - ambiguousCount
        - notComparedCount
        - trustLevel
      properties:
        tenantId:
          type: integer
        tenantName:
          type: string
        compareRunId:
          type:
            - integer
            - 'null'
        compareRunStatus:
          type:
            - string
            - 'null'
        compareRunOutcome:
          type:
            - string
            - 'null'
        freshnessState:
          $ref: '#/components/schemas/FreshnessState'
        lastComparedAt:
          type:
            - string
            - 'null'
          format: date-time
        matchedCount:
          type: integer
        differingCount:
          type: integer
        missingCount:
          type: integer
        ambiguousCount:
          type: integer
        notComparedCount:
          type: integer
        maxSeverity:
          anyOf:
            - $ref: '#/components/schemas/FindingSeverity'
            - type: 'null'
        trustLevel:
          $ref: '#/components/schemas/TrustLevel'
    MatrixSubjectSummary:
      type: object
      additionalProperties: false
      required:
        - subjectKey
        - policyType
        - deviationBreadth
        - missingBreadth
        - ambiguousBreadth
        - notComparedBreadth
        - trustLevel
      properties:
        subjectKey:
          type: string
        policyType:
          type: string
        displayName:
          type:
            - string
            - 'null'
        baselineExternalId:
          type:
            - string
            - 'null'
        deviationBreadth:
          type: integer
        missingBreadth:
          type: integer
        ambiguousBreadth:
          type: integer
        notComparedBreadth:
          type: integer
        maxSeverity:
          anyOf:
            - $ref: '#/components/schemas/FindingSeverity'
            - type: 'null'
        trustLevel:
          $ref: '#/components/schemas/TrustLevel'
    MatrixCell:
      type: object
      additionalProperties: false
      required:
        - tenantId
        - subjectKey
        - state
        - trustLevel
        - policyTypeCovered
      properties:
        tenantId:
          type: integer
        subjectKey:
          type: string
        state:
          $ref: '#/components/schemas/MatrixCellState'
        severity:
          anyOf:
            - $ref: '#/components/schemas/FindingSeverity'
            - type: 'null'
        trustLevel:
          $ref: '#/components/schemas/TrustLevel'
        reasonCode:
          type:
            - string
            - 'null'
        compareRunId:
          type:
            - integer
            - 'null'
        findingId:
          type:
            - integer
            - 'null'
        findingWorkflowState:
          type:
            - string
            - 'null'
        lastComparedAt:
          type:
            - string
            - 'null'
          format: date-time
        policyTypeCovered:
          type: boolean
    MatrixRow:
      type: object
      additionalProperties: false
      required:
        - subject
        - cells
      properties:
        subject:
          $ref: '#/components/schemas/MatrixSubjectSummary'
        cells:
          type: array
          items:
            $ref: '#/components/schemas/MatrixCell'
    MatrixFilterState:
      type: object
      additionalProperties: false
      properties:
        policyTypes:
          type: array
          items:
            type: string
        states:
          type: array
          items:
            $ref: '#/components/schemas/MatrixCellState'
        severities:
          type: array
          items:
            $ref: '#/components/schemas/FindingSeverity'
        tenantSort:
          $ref: '#/components/schemas/TenantSort'
        subjectSort:
          $ref: '#/components/schemas/SubjectSort'
        focusedSubjectKey:
          type:
            - string
            - 'null'
    BaselineCompareMatrixBundle:
      type: object
      additionalProperties: false
      required:
        - reference
        - filters
        - tenantSummaries
        - subjectSummaries
        - rows
      properties:
        reference:
          $ref: '#/components/schemas/MatrixReference'
        filters:
          $ref: '#/components/schemas/MatrixFilterState'
        tenantSummaries:
          type: array
          items:
            $ref: '#/components/schemas/MatrixTenantSummary'
        subjectSummaries:
          type: array
          items:
            $ref: '#/components/schemas/MatrixSubjectSummary'
        rows:
          type: array
          items:
            $ref: '#/components/schemas/MatrixRow'
    CompareAssignedTenantTarget:
      type: object
      additionalProperties: false
      required:
        - tenantId
        - launchState
      properties:
        tenantId:
          type: integer
        runId:
          type:
            - integer
            - 'null'
        launchState:
          type: string
          enum:
            - queued
            - already_queued
            - blocked
        reasonCode:
          type:
            - string
            - 'null'
    CompareAssignedTenantsLaunchResult:
      type: object
      additionalProperties: false
      required:
        - baselineProfileId
        - visibleAssignedTenantCount
        - queuedCount
        - alreadyQueuedCount
        - blockedCount
        - targets
      properties:
        baselineProfileId:
          type: integer
        visibleAssignedTenantCount:
          type: integer
        queuedCount:
          type: integer
        alreadyQueuedCount:
          type: integer
        blockedCount:
          type: integer
        targets:
          type: array
          items:
            $ref: '#/components/schemas/CompareAssignedTenantTarget'