openapi: 3.1.0
info:
  title: Normalized Detail Family Internal Surface Contract
  version: 0.1.0
  summary: Internal logical contract for shared normalized settings and normalized diff families
  description: |
    This contract is an internal planning artifact for Spec 197. It documents the
    family-owned normalized settings and normalized diff surfaces used across
    policy, policy version, and finding detail hosts. Rendered routes still
    return HTML. The structured schemas below describe the internal surface
    contract and approved host-variation boundaries. This does not add a public
    HTTP API.
servers:
  - url: /internal
x-family-consumers:
  - surface: policy_settings
    source: normalized_settings_surface
    accessPattern: infolist_safe
    guardScope:
      - apps/platform/app/Filament/Resources/PolicyResource.php
      - apps/platform/resources/views/filament/infolists/entries/normalized-settings.blade.php
    requiredMarkers:
      - NormalizedSettingsSurface::build
      - data-shared-detail-family="normalized-settings"
      - data-shared-normalized-settings-host="policy"
  - surface: policy_version_settings
    source: normalized_settings_surface
    accessPattern: infolist_safe
    guardScope:
      - apps/platform/app/Filament/Resources/PolicyVersionResource.php
      - apps/platform/resources/views/filament/infolists/entries/normalized-settings.blade.php
    requiredMarkers:
      - NormalizedSettingsSurface::build
      - data-shared-detail-family="normalized-settings"
      - data-shared-normalized-settings-host="policy_version"
    x-forbiddenMarkers:
      - needle: "->view('filament.infolists.entries.policy-settings-standard')"
        max: 0
  - surface: policy_version_diff
    source: normalized_diff_surface
    accessPattern: infolist_safe
    guardScope:
      - apps/platform/app/Filament/Resources/PolicyVersionResource.php
      - apps/platform/resources/views/filament/infolists/entries/normalized-diff.blade.php
    requiredMarkers:
      - NormalizedDiffSurface::build
      - data-shared-detail-family="normalized-diff"
      - data-shared-normalized-diff-host="policy_version"
      - data-shared-zone="summary"
      - data-shared-zone="groups"
  - surface: finding_diff
    source: normalized_diff_surface
    accessPattern: infolist_safe
    guardScope:
      - apps/platform/app/Filament/Resources/FindingResource.php
      - apps/platform/resources/views/filament/infolists/entries/normalized-diff.blade.php
    requiredMarkers:
      - NormalizedDiffSurface::build
      - data-shared-detail-family="normalized-diff"
      - data-shared-normalized-diff-host="finding"
      - data-shared-normalized-diff-state
      - data-shared-zone="summary"
paths:
  /ui-contracts/normalized-settings/resolve:
    get:
      summary: Resolve the shared normalized settings family contract for one host
      operationId: resolveNormalizedSettingsSurface
      parameters:
        - name: host
          in: query
          required: true
          schema:
            $ref: '#/components/schemas/NormalizedSettingsHostKind'
      responses:
        '200':
          description: Shared normalized settings family contract resolved for the current host context
          content:
            application/vnd.tenantpilot.normalized-settings-surface+json:
              schema:
                $ref: '#/components/schemas/NormalizedSettingsSurfaceContract'
        '403':
          description: Actor is in scope but lacks the capability required to view the host
        '404':
          description: Host or tenant scope is not visible in the current workspace or tenant context
  /ui-contracts/normalized-diff/resolve:
    get:
      summary: Resolve the shared normalized diff family contract for one host
      operationId: resolveNormalizedDiffSurface
      parameters:
        - name: host
          in: query
          required: true
          schema:
            $ref: '#/components/schemas/NormalizedDiffHostKind'
      responses:
        '200':
          description: Shared normalized diff family contract resolved for the current host context
          content:
            application/vnd.tenantpilot.normalized-diff-surface+json:
              schema:
                $ref: '#/components/schemas/NormalizedDiffSurfaceContract'
        '403':
          description: Actor is in scope but lacks the capability required to view the host
        '404':
          description: Host or tenant scope is not visible in the current workspace or tenant context
components:
  schemas:
    NormalizedSettingsHostKind:
      type: string
      enum:
        - policy
        - policy_version
    NormalizedDiffHostKind:
      type: string
      enum:
        - policy_version
        - finding
    NormalizedSettingsVariant:
      type: string
      enum:
        - settings_catalog_table
        - standard_blocks
    AvailabilityState:
      type: string
      enum:
        - available
        - unavailable
        - partial
    NormalizedSettingsSectionBehavior:
      type: object
      additionalProperties: false
      required:
        - preservesSectionOrder
        - supportsExpansion
        - ownsEmptyState
      properties:
        preservesSectionOrder:
          type: boolean
        supportsExpansion:
          type: boolean
        ownsEmptyState:
          type: boolean
    NormalizedSettingsRenderExpectations:
      type: object
      additionalProperties: false
      required:
        - ownsWarningsInWrapper
        - ownsSubtypeDelegation
        - keepsHostFramingOutsideCore
      properties:
        ownsWarningsInWrapper:
          type: boolean
        ownsSubtypeDelegation:
          type: boolean
        keepsHostFramingOutsideCore:
          type: boolean
    NormalizedDiffViewMode:
      type: object
      additionalProperties: false
      required:
        - key
        - label
        - default
      properties:
        key:
          type: string
        label:
          type: string
        default:
          type: boolean
    NormalizedDiffSectionBehavior:
      type: object
      additionalProperties: false
      required:
        - preservesGroupOrder
        - supportsExpansion
        - supportsFullscreen
      properties:
        preservesGroupOrder:
          type: boolean
        supportsExpansion:
          type: boolean
        supportsFullscreen:
          type: boolean
    NormalizedDiffRenderExpectations:
      type: object
      additionalProperties: false
      required:
        - ownsAvailabilityState
        - ownsZeroDiffMessaging
        - keepsHostFramingOutsideCore
      properties:
        ownsAvailabilityState:
          type: boolean
        ownsZeroDiffMessaging:
          type: boolean
        keepsHostFramingOutsideCore:
          type: boolean
    NormalizedSettingsSurfaceContract:
      type: object
      additionalProperties: false
      required:
        - hostKind
        - context
        - variant
        - sectionBehavior
        - renderExpectations
        - titlePolicy
      properties:
        hostKind:
          $ref: '#/components/schemas/NormalizedSettingsHostKind'
        context:
          type: string
          enum:
            - policy
            - version
        variant:
          $ref: '#/components/schemas/NormalizedSettingsVariant'
        warnings:
          type: array
          items:
            type: string
        settingsTable:
          type:
            - object
            - 'null'
        blocks:
          type: array
          items:
            type: object
        sectionBehavior:
          $ref: '#/components/schemas/NormalizedSettingsSectionBehavior'
        renderExpectations:
          $ref: '#/components/schemas/NormalizedSettingsRenderExpectations'
        emptyState:
          type:
            - object
            - 'null'
        titlePolicy:
          type: object
          additionalProperties: false
          required:
            - showWrapperTitle
          properties:
            showWrapperTitle:
              type: boolean
    NormalizedDiffSurfaceContract:
      type: object
      additionalProperties: false
      required:
        - hostKind
        - availabilityState
        - summary
        - viewModes
        - sectionBehavior
        - renderExpectations
      properties:
        hostKind:
          $ref: '#/components/schemas/NormalizedDiffHostKind'
        availabilityState:
          $ref: '#/components/schemas/AvailabilityState'
        summary:
          type: object
          additionalProperties: false
          required:
            - added
            - removed
            - changed
          properties:
            added:
              type: integer
            removed:
              type: integer
            changed:
              type: integer
            message:
              type:
                - string
                - 'null'
        viewModes:
          type: array
          items:
            $ref: '#/components/schemas/NormalizedDiffViewMode'
        sectionBehavior:
          $ref: '#/components/schemas/NormalizedDiffSectionBehavior'
        renderExpectations:
          $ref: '#/components/schemas/NormalizedDiffRenderExpectations'
        groups:
          type: array
          items:
            type: object
        scriptRendering:
          type:
            - object
            - 'null'
        emptyState:
          type:
            - object
            - 'null'