openapi: 3.1.0
info:
  title: Finding Governance Health Internal Contract
  version: 0.1.0
  description: |
    Internal admin-plane contract for hardened finding governance and resolution semantics.
    These endpoints represent the server-side data contract backing Filament and Livewire surfaces,
    not a new public API.
servers:
  - url: /api/internal
paths:
  /tenants/{tenantId}/findings:
    get:
      summary: List findings with workflow, governance, and urgency semantics
      operationId: listTenantFindingsWithGovernanceHealth
      tags: [Findings]
      parameters:
        - $ref: '#/components/parameters/TenantId'
        - name: status
          in: query
          schema:
            type: string
            enum: [new, acknowledged, triaged, in_progress, reopened, resolved, closed, risk_accepted]
        - name: governanceValidity
          in: query
          schema:
            type: string
            enum: [valid, expiring, expired, revoked, rejected, missing_support]
        - name: overdue
          in: query
          schema:
            type: boolean
      responses:
        '200':
          description: Findings list rows with operator-facing lifecycle and governance semantics
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/FindingListItem'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /tenants/{tenantId}/findings/{findingId}:
    get:
      summary: View finding detail with leading status and governance zone
      operationId: showFindingWithGovernanceHealth
      tags: [Findings]
      parameters:
        - $ref: '#/components/parameters/TenantId'
        - $ref: '#/components/parameters/FindingId'
      responses:
        '200':
          description: Finding detail payload with primary operator summary and secondary diagnostics
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FindingDetail'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /tenants/{tenantId}/finding-exceptions:
    get:
      summary: List tenant exception records aligned with finding governance semantics
      operationId: listTenantFindingExceptionsForGovernanceHealth
      tags: [Finding Exceptions]
      parameters:
        - $ref: '#/components/parameters/TenantId'
        - name: status
          in: query
          schema:
            type: string
            enum: [pending, active, expiring, expired, rejected, revoked, superseded]
        - name: validity
          in: query
          schema:
            type: string
            enum: [valid, expiring, expired, revoked, rejected, missing_support]
      responses:
        '200':
          description: Tenant exception register rows with governance validity and warnings
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/FindingExceptionSurfaceItem'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /workspaces/{workspaceId}/finding-exceptions/queue:
    get:
      summary: Canonical exception queue with tenant-safe governance attention signals
      operationId: listCanonicalFindingExceptionQueueForGovernanceHealth
      tags: [Finding Exceptions]
      parameters:
        - $ref: '#/components/parameters/WorkspaceId'
        - name: tenantId
          in: query
          schema:
            type: integer
        - name: validity
          in: query
          schema:
            type: string
            enum: [valid, expiring, expired, revoked, rejected, missing_support]
      responses:
        '200':
          description: Canonical queue rows filtered to entitled tenants only
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/FindingExceptionSurfaceItem'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /tenants/{tenantId}/dashboard/needs-attention:
    get:
      summary: Tenant dashboard needs-attention summary including overdue and governance attention
      operationId: showTenantNeedsAttentionSummary
      tags: [Dashboard]
      parameters:
        - $ref: '#/components/parameters/TenantId'
      responses:
        '200':
          description: Read-only summary items for tenant dashboard attention state
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NeedsAttentionSummary'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /tenants/{tenantId}/baseline-compare/summary:
    get:
      summary: Baseline compare summary with honest findings and governance attention cues
      operationId: showBaselineCompareSummaryWithFindingGovernanceContext
      tags: [Baseline Compare]
      parameters:
        - $ref: '#/components/parameters/TenantId'
      responses:
        '200':
          description: Baseline compare summary payload with findings and governance attention context
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BaselineCompareFindingSummary'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
components:
  parameters:
    TenantId:
      name: tenantId
      in: path
      required: true
      schema:
        type: integer
    FindingId:
      name: findingId
      in: path
      required: true
      schema:
        type: integer
    WorkspaceId:
      name: workspaceId
      in: path
      required: true
      schema:
        type: integer
  responses:
    Forbidden:
      description: Member lacks required capability in the current scope
    NotFound:
      description: Workspace or tenant scope is not entitled
  schemas:
    FindingListItem:
      type: object
      required: [id, workflowStatus, workflowFamily, severity, dueAttention, governance]
      properties:
        id:
          type: integer
        workflowStatus:
          type: string
          enum: [new, acknowledged, triaged, in_progress, reopened, resolved, closed, risk_accepted]
        workflowFamily:
          type: string
          enum: [active, accepted_risk, historical]
        severity:
          type: string
          enum: [low, medium, high, critical]
        dueAttention:
          type: string
          enum: [none, due_soon, overdue]
        ownerName:
          type: string
          nullable: true
        assigneeName:
          type: string
          nullable: true
        governance:
          $ref: '#/components/schemas/GovernanceSignal'
    FindingDetail:
      allOf:
        - $ref: '#/components/schemas/FindingListItem'
        - type: object
          properties:
            primaryNextAction:
              type: string
              nullable: true
            governanceWarning:
              type: string
              nullable: true
            resolutionContext:
              type: string
              nullable: true
            diagnostics:
              type: object
              description: Secondary diagnostic context such as run ids, fingerprints, and evidence sections
    FindingExceptionSurfaceItem:
      type: object
      required: [id, status, validityState, findingId]
      properties:
        id:
          type: integer
        findingId:
          type: integer
        tenantId:
          type: integer
          nullable: true
        status:
          type: string
          enum: [pending, active, expiring, expired, rejected, revoked, superseded]
        validityState:
          type: string
          enum: [valid, expiring, expired, revoked, rejected, missing_support]
        governanceWarning:
          type: string
          nullable: true
        reviewDueAt:
          type: string
          format: date-time
          nullable: true
        expiresAt:
          type: string
          format: date-time
          nullable: true
    GovernanceSignal:
      type: object
      required: [attentionState]
      properties:
        validityState:
          type: string
          enum: [valid, expiring, expired, revoked, rejected, missing_support]
          nullable: true
        exceptionStatus:
          type: string
          enum: [pending, active, expiring, expired, rejected, revoked, superseded]
          nullable: true
        attentionState:
          type: string
          enum: [healthy, attention_needed, not_applicable]
        warning:
          type: string
          nullable: true
    NeedsAttentionSummary:
      type: object
      properties:
        items:
          type: array
          items:
            type: object
            required: [title, body, badge]
            properties:
              title:
                type: string
              body:
                type: string
              badge:
                type: string
              badgeColor:
                type: string
              nextStep:
                type: string
                nullable: true
        healthyChecks:
          type: array
          items:
            type: object
            properties:
              title:
                type: string
              body:
                type: string
    BaselineCompareFindingSummary:
      type: object
      properties:
        findingsCount:
          type: integer
        summaryHeadline:
          type: string
        supportingMessage:
          type: string
          nullable: true
        governanceAttentionPresent:
          type: boolean
        overdueFindingsPresent:
          type: boolean
        nextActionLabel:
          type: string
          nullable: true