openapi: 3.1.0
info:
  title: Portfolio Triage Review State Internal Surface Contract
  version: 0.1.0
  summary: Internal logical contract for persisted triage-review state, current-set progress, and operator mutations
  description: |
    This contract is an internal planning artifact for Spec 189. The affected routes still
    render HTML through Filament and Livewire. The schemas below describe the bounded read
    models and mutation payloads that must be derivable or writable before portfolio-triage
    surfaces render review-state badges, progress summaries, or mutation actions.
servers:
  - url: /internal
x-triage-review-consumers:
  - surface: workspace.overview.progress
    sourceFiles:
      - apps/platform/app/Support/Workspaces/WorkspaceOverviewBuilder.php
      - apps/platform/app/Filament/Widgets/Workspace/WorkspaceSummaryStats.php
      - apps/platform/app/Filament/Widgets/Workspace/WorkspaceNeedsAttention.php
    mustRender:
      - concern_family
      - affected_total
      - reviewed_count
      - follow_up_needed_count
      - changed_since_review_count
  - surface: tenant.registry.triage
    sourceFiles:
      - apps/platform/app/Filament/Resources/TenantResource.php
      - apps/platform/app/Filament/Resources/TenantResource/Pages/ListTenants.php
    mustRender:
      - concern_family
      - derived_review_state
      - reviewed_at
      - reviewed_by_user_id
    mustAccept:
      - review_state
      - backup_posture
      - recovery_evidence
      - triage_sort
  - surface: tenant.dashboard.arrival
    sourceFiles:
      - apps/platform/app/Filament/Pages/TenantDashboard.php
      - apps/platform/app/Filament/Widgets/Tenant/TenantTriageArrivalContinuity.php
    mustRender:
      - concern_family
      - derived_review_state
      - mark_reviewed_action
      - mark_follow_up_needed_action
paths:
  /admin:
    get:
      summary: Workspace overview exposes current-set triage progress summaries
      operationId: viewWorkspaceOverviewWithTriageReviewProgress
      responses:
        '200':
          description: Rendered workspace overview with additive progress summary semantics
          content:
            text/html:
              schema:
                type: string
            application/vnd.tenantpilot.workspace-triage-progress+json:
              schema:
                $ref: '#/components/schemas/WorkspaceTriageProgressBundle'
        '404':
          description: Workspace scope is not available to the actor
  /admin/tenants:
    get:
      summary: Tenant registry triage renders review-state badges and accepts review-state filters
      operationId: viewTenantRegistryWithTriageReviewState
      parameters:
        - name: backup_posture
          in: query
          required: false
          schema:
            type: array
            items:
              $ref: '#/components/schemas/BackupConcernState'
        - name: recovery_evidence
          in: query
          required: false
          schema:
            type: array
            items:
              $ref: '#/components/schemas/RecoveryConcernState'
        - name: review_state
          in: query
          required: false
          schema:
            type: array
            items:
              $ref: '#/components/schemas/DerivedReviewState'
        - name: triage_sort
          in: query
          required: false
          schema:
            type: string
            enum:
              - worst_first
      responses:
        '200':
          description: Rendered tenant registry with concern truth plus review-state context
          content:
            text/html:
              schema:
                type: string
            application/vnd.tenantpilot.tenant-registry-triage-review+json:
              schema:
                $ref: '#/components/schemas/TenantRegistryTriageReviewBundle'
        '404':
          description: Workspace scope is not available to the actor
  /admin/t/{tenant}:
    get:
      summary: Tenant dashboard arrival continuity shows the current review state for the focused concern family
      operationId: viewTenantDashboardWithTriageReviewState
      parameters:
        - name: tenant
          in: path
          required: true
          schema:
            type: string
        - name: arrival
          in: query
          required: false
          schema:
            type: string
          description: Existing portfolio-arrival token carrying concern-family focus.
      responses:
        '200':
          description: Rendered tenant dashboard with optional continuity review-state controls
          content:
            text/html:
              schema:
                type: string
            application/vnd.tenantpilot.tenant-dashboard-triage-review+json:
              schema:
                $ref: '#/components/schemas/TenantDashboardTriageReviewBundle'
        '404':
          description: Tenant is outside workspace or tenant entitlement scope
  /internal/workspaces/{workspace}/tenants/{tenant}/triage-review-state:
    put:
      summary: Upsert the active triage-review record for one workspace, tenant, and concern family
      operationId: upsertTenantTriageReviewState
      parameters:
        - name: workspace
          in: path
          required: true
          schema:
            type: integer
        - name: tenant
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TriageReviewMutationRequest'
      responses:
        '200':
          description: Active review record updated and current derived state returned
          content:
            application/vnd.tenantpilot.triage-review-state+json:
              schema:
                $ref: '#/components/schemas/TriageReviewMutationResult'
        '403':
          description: Actor is in scope but lacks the capability to mutate triage review state
        '404':
          description: Workspace or tenant is outside the actor's entitlement scope
components:
  schemas:
    ConcernFamily:
      type: string
      enum:
        - backup_health
        - recovery_evidence
    BackupConcernState:
      type: string
      enum:
        - absent
        - stale
        - degraded
    RecoveryConcernState:
      type: string
      enum:
        - unvalidated
        - weakened
    ConcernState:
      type: string
      enum:
        - absent
        - stale
        - degraded
        - unvalidated
        - weakened
    ManualReviewState:
      type: string
      enum:
        - reviewed
        - follow_up_needed
    DerivedReviewState:
      type: string
      enum:
        - not_reviewed
        - reviewed
        - follow_up_needed
        - changed_since_review
    TriageReviewSnapshot:
      type: object
      additionalProperties: false
      required:
        - concernFamily
        - concernState
      properties:
        concernFamily:
          $ref: '#/components/schemas/ConcernFamily'
        concernState:
          $ref: '#/components/schemas/ConcernState'
        reasonCode:
          type:
            - string
            - 'null'
        severityKey:
          type:
            - string
            - 'null'
        supportingKey:
          type:
            - string
            - 'null'
    ActiveTriageReviewRecord:
      type: object
      additionalProperties: false
      required:
        - workspaceId
        - tenantId
        - concernFamily
        - currentState
        - reviewedAt
        - reviewFingerprint
      properties:
        workspaceId:
          type: integer
        tenantId:
          type: integer
        concernFamily:
          $ref: '#/components/schemas/ConcernFamily'
        currentState:
          $ref: '#/components/schemas/ManualReviewState'
        reviewedAt:
          type: string
          format: date-time
        reviewedByUserId:
          type:
            - integer
            - 'null'
        reviewFingerprint:
          type: string
        reviewSnapshot:
          $ref: '#/components/schemas/TriageReviewSnapshot'
        lastSeenMatchingAt:
          type:
            - string
            - 'null'
          format: date-time
        resolvedAt:
          type:
            - string
            - 'null'
          format: date-time
    ResolvedTriageReviewState:
      type: object
      additionalProperties: false
      required:
        - concernFamily
        - derivedState
        - currentConcernPresent
      properties:
        concernFamily:
          $ref: '#/components/schemas/ConcernFamily'
        derivedState:
          $ref: '#/components/schemas/DerivedReviewState'
        currentConcernPresent:
          type: boolean
        currentFingerprint:
          type:
            - string
            - 'null'
        reviewedAt:
          type:
            - string
            - 'null'
          format: date-time
        reviewedByUserId:
          type:
            - integer
            - 'null'
        snapshot:
          anyOf:
            - $ref: '#/components/schemas/TriageReviewSnapshot'
            - type: 'null'
    TriageProgressSummary:
      type: object
      additionalProperties: false
      required:
        - concernFamily
        - affectedTotal
        - reviewedCount
        - followUpNeededCount
        - changedSinceReviewCount
        - notReviewedCount
      properties:
        concernFamily:
          $ref: '#/components/schemas/ConcernFamily'
        affectedTotal:
          type: integer
        reviewedCount:
          type: integer
        followUpNeededCount:
          type: integer
        changedSinceReviewCount:
          type: integer
        notReviewedCount:
          type: integer
    TriageReviewMutationRequest:
      type: object
      additionalProperties: false
      required:
        - concernFamily
        - state
        - currentFingerprint
        - snapshot
      properties:
        concernFamily:
          $ref: '#/components/schemas/ConcernFamily'
        state:
          $ref: '#/components/schemas/ManualReviewState'
        currentFingerprint:
          type: string
        snapshot:
          $ref: '#/components/schemas/TriageReviewSnapshot'
        sourceSurface:
          type:
            - string
            - 'null'
          enum:
            - tenant_registry
            - tenant_dashboard_arrival
            - null
    TriageReviewMutationResult:
      type: object
      additionalProperties: false
      required:
        - activeRecord
        - resolvedState
      properties:
        activeRecord:
          $ref: '#/components/schemas/ActiveTriageReviewRecord'
        resolvedState:
          $ref: '#/components/schemas/ResolvedTriageReviewState'
    WorkspaceTriageProgressBundle:
      type: object
      additionalProperties: false
      required:
        - summaries
      properties:
        summaries:
          type: array
          items:
            $ref: '#/components/schemas/TriageProgressSummary'
    TenantRegistryRowReviewState:
      type: object
      additionalProperties: false
      required:
        - tenantId
        - concernFamily
        - derivedState
      properties:
        tenantId:
          type: integer
        concernFamily:
          $ref: '#/components/schemas/ConcernFamily'
        derivedState:
          $ref: '#/components/schemas/DerivedReviewState'
        reviewedAt:
          type:
            - string
            - 'null'
          format: date-time
        reviewedByUserId:
          type:
            - integer
            - 'null'
    TenantRegistryTriageReviewBundle:
      type: object
      additionalProperties: false
      required:
        - rows
      properties:
        concernFamilyFocus:
          type:
            - string
            - 'null'
          enum:
            - backup_health
            - recovery_evidence
            - null
        rows:
          type: array
          items:
            $ref: '#/components/schemas/TenantRegistryRowReviewState'
        activeFilters:
          type:
            - object
            - 'null'
          additionalProperties: true
    TenantDashboardTriageReviewBundle:
      type: object
      additionalProperties: false
      required:
        - canRenderReviewControls
      properties:
        concernFamilyFocus:
          anyOf:
            - $ref: '#/components/schemas/ConcernFamily'
            - type: 'null'
        reviewState:
          anyOf:
            - $ref: '#/components/schemas/ResolvedTriageReviewState'
            - type: 'null'
        canRenderReviewControls:
          type: boolean
        markReviewedAllowed:
          type: boolean
        markFollowUpNeededAllowed:
          type: boolean