openapi: 3.1.0
info:
  title: Tenant Dashboard Truth Alignment Internal Surface Contract
  version: 0.1.0
  summary: Internal logical contract for aligned tenant dashboard KPI, attention, compare, and recency surfaces
  description: |
    This contract is an internal planning artifact for Spec 173. It documents how
    the tenant dashboard's summary and recency surfaces must derive their meaning
    from existing tenant truth and how drill-through destinations must preserve
    that meaning. The rendered routes still return HTML. The structured schemas
    below describe the internal page and widget models that must be derivable
    before rendering. This does not add a public HTTP API.
servers:
  - url: /internal
x-dashboard-consumers:
  - surface: tenant.dashboard.kpis
    summarySource:
      - finding_status_helpers
      - finding_destination_filters
      - canonical_operations_links
    guardScope:
      - app/Filament/Widgets/Dashboard/DashboardKpis.php
    expectedContract:
      - each_kpi_label_matches_its_count_universe
      - each_kpi_destination_reproduces_or_explicitly_broadens_the_named_subset
  - surface: tenant.dashboard.needs_attention
    summarySource:
      - tenant_governance_aggregate
      - operation_run_activity
    guardScope:
      - app/Filament/Widgets/Dashboard/NeedsAttention.php
    expectedContract:
      - each_primary_item_has_one_tenant_safe_destination
      - healthy_fallback_is_hidden_when_any_attention_condition_exists
  - surface: tenant.dashboard.baseline_compare_now
    summarySource:
      - tenant_governance_aggregate
      - baseline_compare_summary_assessment
    guardScope:
      - app/Filament/Widgets/Dashboard/BaselineCompareNow.php
    expectedContract:
      - positive_compare_claims_do_not_outvote_stronger_attention_conditions
      - primary_compare_destination_uses_existing_baseline_compare_landing
  - surface: tenant.dashboard.recent_drift_findings
    summarySource:
      - recent_drift_query
    guardScope:
      - app/Filament/Widgets/Dashboard/RecentDriftFindings.php
    expectedContract:
      - surface_role_is_diagnostic_recency_not_primary_queue
      - row_click_uses_canonical_finding_detail
  - surface: tenant.dashboard.recent_operations
    summarySource:
      - recent_operations_query
      - canonical_operations_links
    guardScope:
      - app/Filament/Widgets/Dashboard/RecentOperations.php
    expectedContract:
      - surface_role_is_diagnostic_recency_not_primary_queue
      - row_click_uses_canonical_operation_detail
paths:
  /admin/t/{tenant}:
    get:
      summary: Render the aligned tenant dashboard summary bundle
      operationId: viewTenantDashboardAlignedTruth
      parameters:
        - name: tenant
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Tenant dashboard rendered with aligned KPI, attention, compare, and recency semantics
          content:
            text/html:
              schema:
                type: string
            application/vnd.tenantpilot.tenant-dashboard-truth+json:
              schema:
                $ref: '#/components/schemas/TenantDashboardTruthBundle'
        '404':
          description: Tenant is outside workspace or tenant entitlement scope
  /admin/t/{tenant}/findings:
    get:
      summary: Tenant findings destination used by KPI and attention drill-throughs
      operationId: openTenantFindingsFromDashboard
      parameters:
        - name: tenant
          in: path
          required: true
          schema:
            type: string
        - name: tab
          in: query
          required: false
          schema:
            $ref: '#/components/schemas/FindingsTab'
        - name: high_severity
          in: query
          required: false
          schema:
            type: boolean
        - name: status
          in: query
          required: false
          schema:
            type: string
        - name: finding_type
          in: query
          required: false
          schema:
            type: string
      responses:
        '200':
          description: Tenant findings list opened with tenant-safe dashboard continuity filters
        '403':
          description: Actor is in scope but lacks findings inspection capability
        '404':
          description: Tenant is outside workspace or tenant entitlement scope
  /admin/t/{tenant}/baseline-compare-landing:
    get:
      summary: Tenant baseline compare landing used by compare and attention drill-throughs
      operationId: openTenantBaselineCompareLandingFromDashboard
      parameters:
        - name: tenant
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Tenant baseline compare landing opened with the same tenant-context compare posture the dashboard summarized
        '403':
          description: Actor is in scope but lacks baseline compare inspection capability
        '404':
          description: Tenant is outside workspace or tenant entitlement scope
  /admin/t/{tenant}/findings/{record}:
    get:
      summary: Tenant finding detail opened from recent drift row-click inspection
      operationId: openTenantFindingDetailFromDashboardRecency
      parameters:
        - name: tenant
          in: path
          required: true
          schema:
            type: string
        - name: record
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Tenant finding detail opened from the recent drift diagnostic surface
        '403':
          description: Actor is in scope but lacks finding detail inspection capability
        '404':
          description: Tenant or finding is outside entitlement scope
  /admin/operations:
    get:
      summary: Canonical operations destination with tenant-prefilter continuity from the tenant dashboard
      operationId: openCanonicalOperationsFromDashboard
      parameters:
        - name: tenant_id
          in: query
          required: false
          schema:
            type:
              - integer
              - string
          description: Tenant filter carried forward from tenant-context dashboard navigation.
        - name: activeTab
          in: query
          required: false
          description: Uses `active` for healthy queued or running activity, `blocked` for warning, stalled, or unusually long-running follow-up needing review, and `failed` for terminal failure follow-up.
          schema:
            $ref: '#/components/schemas/OperationsTab'
        - name: navigationContext
          in: query
          required: false
          schema:
            type: string
          description: Optional serialized canonical navigation context carried from tenant dashboard drill-throughs.
      responses:
        '200':
          description: Canonical admin operations list filtered to the originating tenant when opened from the dashboard
        '403':
          description: Actor is in scope but lacks operations inspection capability
        '404':
          description: Tenant context is outside entitlement scope
  /admin/operations/{run}:
    get:
      summary: Canonical operation detail opened from recent operations row-click inspection
      operationId: openOperationDetailFromDashboardRecency
      parameters:
        - name: run
          in: path
          required: true
          schema:
            type:
              - integer
              - string
      responses:
        '200':
          description: Canonical operation detail opened from the recent operations diagnostic surface
        '403':
          description: Actor is in scope but lacks operation detail inspection capability
        '404':
          description: Operation run is outside entitlement scope
components:
  schemas:
    FindingsTab:
      type: string
      enum:
        - all
        - needs_action
        - overdue
        - risk_accepted
        - resolved
    OperationsTab:
      type: string
      description: Shared canonical operations tab semantics where `active` represents healthy queued or running work, `blocked` reproduces warning, stalled, or unusually long-running follow-up, and `failed` reproduces terminal failure follow-up.
      enum:
        - all
        - active
        - blocked
        - succeeded
        - partial
        - failed
    ProblemFamily:
      type: string
      enum:
        - findings
        - governance
        - compare
        - operations
    FindingUniverse:
      type: string
      enum:
        - new_drift_only
        - open_drift
        - active_findings
    SeverityUniverse:
      type: string
      enum:
        - high_only
        - high_and_critical
    FindingsDestinationFilterState:
      type: object
      additionalProperties: false
      required:
        - tenant
      properties:
        tenant:
          type: string
        tab:
          oneOf:
            - $ref: '#/components/schemas/FindingsTab'
            - type: 'null'
        status:
          type:
            - string
            - 'null'
        high_severity:
          type:
            - boolean
            - 'null'
        finding_type:
          type:
            - string
            - 'null'
    OperationsDestinationFilterState:
      type: object
      additionalProperties: false
      required:
        - workspace_id
        - tenant_id
      properties:
        workspace_id:
          type: integer
        tenant_id:
          type:
            - integer
            - string
        activeTab:
          oneOf:
            - $ref: '#/components/schemas/OperationsTab'
            - type: 'null'
        navigationContext:
          type:
            - string
            - 'null'
    DestinationKind:
      type: string
      enum:
        - tenant_findings
        - baseline_compare_landing
        - canonical_operations
        - operation_detail
        - finding_detail
        - none
    SurfaceDestination:
      type: object
      additionalProperties: false
      allOf:
        - if:
            properties:
              actionDisabled:
                const: true
          then:
            required:
              - helperText
      required:
        - kind
        - tenantScoped
        - semanticsLabel
      properties:
        kind:
          $ref: '#/components/schemas/DestinationKind'
        tenantScoped:
          type: boolean
        semanticsLabel:
          type: string
        filterState:
          oneOf:
            - $ref: '#/components/schemas/FindingsDestinationFilterState'
            - $ref: '#/components/schemas/OperationsDestinationFilterState'
            - type: 'null'
        actionDisabled:
          type:
            - boolean
            - 'null'
        helperText:
          type:
            - string
            - 'null'
    ActionableDestinationKind:
      type: string
      enum:
        - tenant_findings
        - baseline_compare_landing
        - canonical_operations
    KpiDestinationKind:
      type: string
      enum:
        - tenant_findings
        - canonical_operations
        - none
    ActionableSurfaceDestination:
      allOf:
        - $ref: '#/components/schemas/SurfaceDestination'
        - type: object
          properties:
            kind:
              $ref: '#/components/schemas/ActionableDestinationKind'
    KpiSurfaceDestination:
      allOf:
        - $ref: '#/components/schemas/SurfaceDestination'
        - type: object
          properties:
            kind:
              $ref: '#/components/schemas/KpiDestinationKind'
    KpiMetric:
      type: object
      additionalProperties: false
      required:
        - key
        - label
        - count
        - problemFamily
        - destination
      properties:
        key:
          type: string
        label:
          type: string
        count:
          type: integer
          minimum: 0
        problemFamily:
          type: string
          enum:
            - findings
            - operations
        findingUniverse:
          oneOf:
            - $ref: '#/components/schemas/FindingUniverse'
            - type: 'null'
        severityUniverse:
          oneOf:
            - type: string
              enum:
                - high_only
                - high_and_critical
            - type: 'null'
        destination:
          $ref: '#/components/schemas/KpiSurfaceDestination'
    AttentionItem:
      type: object
      additionalProperties: false
      anyOf:
        - required:
            - actionLabel
        - required:
            - nextStepLabel
        - properties:
            actionDisabled:
              const: true
          required:
            - actionDisabled
            - helperText
      required:
        - key
        - title
        - body
        - badge
        - tone
        - problemFamily
        - destination
      properties:
        key:
          type: string
        title:
          type: string
        body:
          type: string
        supportingMessage:
          type:
            - string
            - 'null'
        badge:
          type: string
        tone:
          type: string
          enum:
            - success
            - warning
            - danger
            - info
            - gray
        problemFamily:
          $ref: '#/components/schemas/ProblemFamily'
        actionLabel:
          type:
            - string
            - 'null'
        actionDisabled:
          type:
            - boolean
            - 'null'
        helperText:
          type:
            - string
            - 'null'
        nextStepLabel:
          type:
            - string
            - 'null'
        destination:
          $ref: '#/components/schemas/ActionableSurfaceDestination'
    CompareSummary:
      type: object
      additionalProperties: false
      required:
        - stateFamily
        - tone
        - headline
        - positiveClaimAllowed
        - nextAction
      properties:
        stateFamily:
          type: string
          enum:
            - positive
            - caution
            - stale
            - action_required
            - in_progress
            - unavailable
        tone:
          type: string
          enum:
            - success
            - warning
            - danger
            - info
            - gray
        headline:
          type: string
        supportingMessage:
          type:
            - string
            - 'null'
        positiveClaimAllowed:
          type: boolean
        nextAction:
          $ref: '#/components/schemas/SurfaceDestination'
    DiagnosticSurfaceSummary:
      type: object
      additionalProperties: false
      required:
        - heading
        - role
        - doesNotDefinePosture
        - fullRowClick
        - detailDestinationKind
      properties:
        heading:
          type: string
        role:
          type: string
          enum:
            - diagnostic_recency
        doesNotDefinePosture:
          type: boolean
        fullRowClick:
          type: boolean
        detailDestinationKind:
          type: string
          enum:
            - finding_detail
            - operation_detail
    TenantDashboardTruthBundle:
      type: object
      additionalProperties: false
      required:
        - tenantId
        - workspaceId
        - kpis
        - attentionItems
        - compareSummary
        - recentFindings
        - recentOperations
      properties:
        tenantId:
          type: integer
        workspaceId:
          type: integer
        kpis:
          type: array
          items:
            $ref: '#/components/schemas/KpiMetric'
        attentionItems:
          type: array
          items:
            $ref: '#/components/schemas/AttentionItem'
        compareSummary:
          $ref: '#/components/schemas/CompareSummary'
        recentFindings:
          $ref: '#/components/schemas/DiagnosticSurfaceSummary'
        recentOperations:
          $ref: '#/components/schemas/DiagnosticSurfaceSummary'