openapi: 3.1.0
info:
  title: Governance Subject Taxonomy and Baseline Scope V2 Internal Contract
  version: 0.1.0
  summary: Internal logical contract for canonical baseline scope, taxonomy listing, save-forward writes, and normalized baseline operation starts
  description: |
    This contract is an internal planning artifact for Spec 202. The affected
    surfaces still render through Filament and Livewire, and baseline capture or
    compare continues to run through the existing Laravel services and jobs. The
    schemas below define the canonical baseline scope document, the governance
    subject taxonomy registry, legacy normalization behavior, and the effective
    scope that capture and compare must consume. The path entries below are
    logical boundary identifiers for existing Filament, Livewire, and service
    entry points only; they do not imply new HTTP controllers or routes.
x-logical-artifact: true
x-governance-subject-taxonomy-consumers:
  - surface: baseline.profile.form
    sourceFiles:
      - apps/platform/app/Filament/Resources/BaselineProfileResource.php
      - apps/platform/app/Filament/Resources/BaselineProfileResource/Pages/CreateBaselineProfile.php
      - apps/platform/app/Filament/Resources/BaselineProfileResource/Pages/EditBaselineProfile.php
    mustRender:
      - normalized_scope_summary
      - active_subject_groups
      - support_readiness
      - invalid_scope_feedback
    mustAccept:
      - legacy_scope_input
      - canonical_scope_v2
  - surface: baseline.profile.detail
    sourceFiles:
      - apps/platform/app/Filament/Resources/BaselineProfileResource/Pages/ViewBaselineProfile.php
    mustRender:
      - canonical_scope_summary
      - support_readiness
      - normalization_lineage_on_demand
  - surface: baseline.scope.backfill.command
    sourceFiles:
      - apps/platform/app/Console/Commands/BackfillBaselineScopeV2.php
    mustAccept:
      - preview_mode_by_default
      - explicit_write_confirmation
    mustProduce:
      - candidate_rewrite_summary
      - committed_rewrite_summary
      - committed_write_audit_logging
  - surface: baseline.capture.start
    sourceFiles:
      - apps/platform/app/Services/Baselines/BaselineCaptureService.php
    mustConsume:
      - effective_scope_v2
      - capture_eligible_subject_types
      - compatibility_projection_if_needed
  - surface: baseline.compare.start
    sourceFiles:
      - apps/platform/app/Services/Baselines/BaselineCompareService.php
    mustConsume:
      - effective_scope_v2
      - compare_eligible_subject_types
      - compatibility_projection_if_needed
paths:
  /internal/workspaces/{workspace}/governance-subject-taxonomy/baseline-subject-types:
    get:
      summary: List active baseline-selectable governance subject types for the current workspace context
      operationId: listBaselineSubjectTypes
      parameters:
        - name: workspace
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Grouped taxonomy metadata for baseline scope selection and validation
          content:
            application/vnd.tenantpilot.governance-taxonomy+json:
              schema:
                $ref: '#/components/schemas/GovernanceSubjectTaxonomyRegistry'
        '403':
          description: Actor is in scope but lacks workspace baseline view capability
        '404':
          description: Workspace is outside actor scope
  /internal/workspaces/{workspace}/baseline-scope/normalize:
    post:
      summary: Normalize legacy or canonical scope input into Baseline Scope V2
      operationId: normalizeBaselineScope
      parameters:
        - name: workspace
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LegacyOrV2ScopeInput'
      responses:
        '200':
          description: Canonical V2 scope plus summary and validation detail
          content:
            application/vnd.tenantpilot.baseline-scope-normalized+json:
              schema:
                $ref: '#/components/schemas/BaselineScopeNormalizationResult'
        '422':
          description: Scope input is invalid or ambiguous after normalization
          content:
            application/vnd.tenantpilot.baseline-scope-errors+json:
              schema:
                $ref: '#/components/schemas/BaselineScopeValidationErrors'
        '403':
          description: Actor is in scope but lacks workspace baseline manage capability
        '404':
          description: Workspace is outside actor scope
  /internal/workspaces/{workspace}/baseline-scope/backfill:
    post:
      summary: Logical maintenance boundary for previewing or committing baseline profile scope backfill
      operationId: backfillBaselineProfileScopeV2
      description: Logical-only maintenance contract for `baseline_profiles.scope_jsonb`; compare assignment overrides remain tolerant-read only in this release.
      parameters:
        - name: workspace
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BaselineScopeBackfillRequest'
      responses:
        '200':
          description: Preview or commit summary for the baseline profile scope backfill command
          content:
            application/vnd.tenantpilot.baseline-scope-backfill+json:
              schema:
                $ref: '#/components/schemas/BaselineScopeBackfillResult'
        '403':
          description: Actor is in scope but lacks workspace baseline manage capability
        '404':
          description: Workspace is outside actor scope
  /admin/baseline-profiles:
    post:
      summary: Create a baseline profile using a scope request that is canonicalized to V2 before persistence
      operationId: createBaselineProfileWithCanonicalScope
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BaselineProfileWriteRequest'
      responses:
        '201':
          description: Baseline profile created with canonical V2 scope persisted
          content:
            application/vnd.tenantpilot.baseline-profile+json:
              schema:
                $ref: '#/components/schemas/BaselineProfileScopeEnvelope'
        '422':
          description: Scope validation failed
        '403':
          description: Actor is in scope but lacks workspace baseline manage capability
        '404':
          description: Workspace is outside actor scope
  /admin/baseline-profiles/{profile}:
    patch:
      summary: Update a baseline profile and save scope forward as canonical V2
      operationId: updateBaselineProfileWithCanonicalScope
      parameters:
        - name: profile
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BaselineProfileWriteRequest'
      responses:
        '200':
          description: Baseline profile updated with canonical V2 scope persisted
          content:
            application/vnd.tenantpilot.baseline-profile+json:
              schema:
                $ref: '#/components/schemas/BaselineProfileScopeEnvelope'
        '422':
          description: Scope validation failed
        '403':
          description: Actor is in scope but lacks workspace baseline manage capability
        '404':
          description: Workspace or baseline profile is outside actor scope
  /internal/tenants/{tenant}/baseline-profiles/{profile}/capture:
    post:
      summary: Start baseline capture using normalized effective scope
      operationId: startBaselineCaptureWithNormalizedScope
      parameters:
        - name: tenant
          in: path
          required: true
          schema:
            type: integer
        - name: profile
          in: path
          required: true
          schema:
            type: integer
      responses:
        '202':
          description: Baseline capture accepted with canonical effective scope recorded in operation context
          content:
            application/vnd.tenantpilot.baseline-operation+json:
              schema:
                $ref: '#/components/schemas/BaselineOperationEnvelope'
        '422':
          description: Requested scope is invalid or includes unsupported capture subject types
        '403':
          description: Actor is in scope but lacks capability to start capture
        '404':
          description: Tenant or profile is outside actor scope
  /internal/tenants/{tenant}/baseline-profiles/{profile}/compare:
    post:
      summary: Start baseline compare using normalized effective scope
      operationId: startBaselineCompareWithNormalizedScope
      parameters:
        - name: tenant
          in: path
          required: true
          schema:
            type: integer
        - name: profile
          in: path
          required: true
          schema:
            type: integer
      responses:
        '202':
          description: Baseline compare accepted with canonical effective scope recorded in operation context
          content:
            application/vnd.tenantpilot.baseline-operation+json:
              schema:
                $ref: '#/components/schemas/BaselineOperationEnvelope'
        '422':
          description: Requested scope is invalid or includes unsupported compare subject types
        '403':
          description: Actor is in scope but lacks capability to start compare
        '404':
          description: Tenant or profile is outside actor scope
components:
  schemas:
    GovernanceDomainKey:
      type: string
      description: Current active values are `intune` and `platform_foundation`; additional domain keys may be introduced later without changing the V2 contract shape.
      examples:
        - intune
        - platform_foundation
        - entra
    GovernanceSubjectClass:
      type: string
      enum:
        - policy
        - configuration_resource
        - posture_dimension
        - control
    GovernanceSubjectType:
      type: object
      additionalProperties: false
      required:
        - domain_key
        - subject_class
        - subject_type_key
        - label
        - description
        - capture_supported
        - compare_supported
        - inventory_supported
        - active
      properties:
        domain_key:
          $ref: '#/components/schemas/GovernanceDomainKey'
        subject_class:
          $ref: '#/components/schemas/GovernanceSubjectClass'
        subject_type_key:
          type: string
        label:
          type: string
        description:
          type:
            - string
            - 'null'
        capture_supported:
          type: boolean
        compare_supported:
          type: boolean
        inventory_supported:
          type: boolean
        active:
          type: boolean
        support_mode:
          type:
            - string
            - 'null'
        legacy_bucket:
          type:
            - string
            - 'null'
    GovernanceSubjectTaxonomyRegistry:
      type: object
      additionalProperties: false
      required:
        - subject_types
      properties:
        subject_types:
          type: array
          items:
            $ref: '#/components/schemas/GovernanceSubjectType'
    LegacyBaselineScopePayload:
      type: object
      additionalProperties: false
      minProperties: 1
      properties:
        policy_types:
          type: array
          description: Empty or omitted means all supported Intune policy subject types when the other legacy bucket is present.
          items:
            type: string
        foundation_types:
          type: array
          description: Empty or omitted means no foundation subject types when the other legacy bucket is present.
          items:
            type: string
    BaselineScopeEntryV2:
      type: object
      additionalProperties: false
      required:
        - domain_key
        - subject_class
        - subject_type_keys
      properties:
        domain_key:
          $ref: '#/components/schemas/GovernanceDomainKey'
        subject_class:
          $ref: '#/components/schemas/GovernanceSubjectClass'
        subject_type_keys:
          type: array
          minItems: 1
          items:
            type: string
        filters:
          type: object
          additionalProperties: true
          default: {}
    BaselineScopeDocumentV2:
      type: object
      additionalProperties: false
      required:
        - version
        - entries
      properties:
        version:
          type: integer
          enum:
            - 2
        entries:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/BaselineScopeEntryV2'
    LegacyOrV2ScopeInput:
      oneOf:
        - $ref: '#/components/schemas/LegacyBaselineScopePayload'
        - $ref: '#/components/schemas/BaselineScopeDocumentV2'
    BaselineScopeSummaryGroup:
      type: object
      additionalProperties: false
      required:
        - domain_key
        - subject_class
        - group_label
        - selected_subject_types
        - capture_supported_count
        - compare_supported_count
      properties:
        domain_key:
          $ref: '#/components/schemas/GovernanceDomainKey'
        subject_class:
          $ref: '#/components/schemas/GovernanceSubjectClass'
        group_label:
          type: string
        selected_subject_types:
          description: Operator-facing selected subject labels for the group, not raw subject type keys.
          type: array
          items:
            type: string
        capture_supported_count:
          type: integer
        compare_supported_count:
          type: integer
        inactive_count:
          type: integer
    BaselineScopeNormalizationResult:
      type: object
      additionalProperties: false
      required:
        - canonical_scope
        - normalization_lineage
        - summary
      properties:
        canonical_scope:
          $ref: '#/components/schemas/BaselineScopeDocumentV2'
        normalization_lineage:
          $ref: '#/components/schemas/BaselineScopeNormalizationLineage'
        summary:
          type: array
          items:
            $ref: '#/components/schemas/BaselineScopeSummaryGroup'
        legacy_projection:
          type:
            - object
            - 'null'
          additionalProperties:
            type: array
            items:
              type: string
    BaselineScopeValidationError:
      type: object
      additionalProperties: false
      required:
        - code
        - message
      properties:
        code:
          type: string
        message:
          type: string
        path:
          type:
            - string
            - 'null'
    BaselineScopeValidationErrors:
      type: object
      additionalProperties: false
      required:
        - errors
      properties:
        errors:
          type: array
          items:
            $ref: '#/components/schemas/BaselineScopeValidationError'
    BaselineProfileWriteRequest:
      type: object
      additionalProperties: false
      required:
        - name
        - status
        - capture_mode
        - requested_scope
      properties:
        name:
          type: string
        description:
          type:
            - string
            - 'null'
        status:
          type: string
        capture_mode:
          type: string
        version_label:
          type:
            - string
            - 'null'
        requested_scope:
          $ref: '#/components/schemas/LegacyOrV2ScopeInput'
    BaselineProfileScopeEnvelope:
      type: object
      additionalProperties: false
      required:
        - profile_id
        - persisted_scope
        - normalization_lineage
        - summary
      properties:
        profile_id:
          type: integer
        persisted_scope:
          $ref: '#/components/schemas/BaselineScopeDocumentV2'
        normalization_lineage:
          $ref: '#/components/schemas/BaselineScopeNormalizationLineage'
        summary:
          type: array
          items:
            $ref: '#/components/schemas/BaselineScopeSummaryGroup'
    BaselineScopeNormalizationLineage:
      type: object
      additionalProperties: false
      required:
        - source_shape
        - normalized_on_read
        - legacy_keys_present
        - save_forward_required
      properties:
        source_shape:
          type: string
          enum:
            - legacy
            - canonical_v2
        normalized_on_read:
          type: boolean
        legacy_keys_present:
          type: array
          items:
            type: string
        save_forward_required:
          type: boolean
    EffectiveBaselineScope:
      type: object
      additionalProperties: false
      required:
        - canonical_scope
        - selected_type_keys
        - allowed_type_keys
        - limited_type_keys
        - unsupported_type_keys
      properties:
        canonical_scope:
          $ref: '#/components/schemas/BaselineScopeDocumentV2'
        selected_type_keys:
          type: array
          items:
            type: string
        allowed_type_keys:
          type: array
          items:
            type: string
        limited_type_keys:
          type: array
          items:
            type: string
        unsupported_type_keys:
          type: array
          items:
            type: string
        capabilities_by_type:
          type: object
          additionalProperties: true
        legacy_projection:
          type:
            - object
            - 'null'
          additionalProperties:
            type: array
            items:
              type: string
    BaselineOperationEnvelope:
      type: object
      additionalProperties: false
      required:
        - profile_id
        - tenant_id
        - operation_type
        - effective_scope
      properties:
        profile_id:
          type: integer
        tenant_id:
          type: integer
        operation_type:
          type: string
          enum:
            - baseline_capture
            - baseline_compare
        effective_scope:
          $ref: '#/components/schemas/EffectiveBaselineScope'
        run_id:
          type:
            - integer
            - 'null'
    BaselineScopeBackfillRequest:
      type: object
      additionalProperties: false
      required:
        - dry_run
      properties:
        dry_run:
          type: boolean
          default: true
        write_confirmed:
          type: boolean
          default: false
    BaselineScopeBackfillResult:
      type: object
      additionalProperties: false
      required:
        - mode
        - candidate_count
        - rewritten_count
        - audit_logged
        - scope_surface
      properties:
        mode:
          type: string
          enum:
            - preview
            - commit
        candidate_count:
          type: integer
        rewritten_count:
          type: integer
        audit_logged:
          type: boolean
        scope_surface:
          type: string
          enum:
            - baseline_profiles_only