openapi: 3.1.0 info: title: Finding Outcome Taxonomy Logical Contract version: 0.1.0 description: | Logical contract for the findings outcome taxonomy feature. This is not a new public HTTP API commitment. It documents the request and response shapes that existing Filament and service workflows must converge on. servers: - url: https://tenantpilot.local description: Logical base URL only tags: - name: Findings - name: FindingsInternal paths: /tenants/{tenantId}/findings: get: tags: [Findings] summary: List tenant findings with terminal-outcome filters operationId: listTenantFindings parameters: - $ref: '#/components/parameters/TenantId' - name: status in: query schema: $ref: '#/components/schemas/FindingStatus' - name: terminal_outcome in: query schema: $ref: '#/components/schemas/TerminalOutcomeKey' - name: verification_state in: query schema: $ref: '#/components/schemas/VerificationState' responses: '200': description: Tenant findings list content: application/json: schema: type: object required: [data] properties: data: type: array items: $ref: '#/components/schemas/FindingSummary' /tenants/{tenantId}/findings/{findingId}: get: tags: [Findings] summary: Get one finding with current terminal-outcome semantics operationId: getTenantFinding parameters: - $ref: '#/components/parameters/TenantId' - $ref: '#/components/parameters/FindingId' responses: '200': description: Finding detail content: application/json: schema: $ref: '#/components/schemas/FindingDetail' /tenants/{tenantId}/findings/{findingId}/resolve: post: tags: [Findings] summary: Resolve a finding with a bounded operator reason operationId: resolveTenantFinding parameters: - $ref: '#/components/parameters/TenantId' - $ref: '#/components/parameters/FindingId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ResolveFindingRequest' responses: '200': description: Finding resolved pending verification content: application/json: schema: $ref: '#/components/schemas/FindingDetail' /tenants/{tenantId}/findings/{findingId}/close: post: tags: [Findings] summary: Close a finding with a bounded administrative reason operationId: closeTenantFinding parameters: - $ref: '#/components/parameters/TenantId' - $ref: '#/components/parameters/FindingId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CloseFindingRequest' responses: '200': description: Finding closed with a non-remediation outcome content: application/json: schema: $ref: '#/components/schemas/FindingDetail' /tenants/{tenantId}/findings/{findingId}/reopen: post: tags: [Findings] summary: Reopen a terminal finding with a bounded reopen reason operationId: reopenTenantFinding parameters: - $ref: '#/components/parameters/TenantId' - $ref: '#/components/parameters/FindingId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ReopenFindingRequest' responses: '200': description: Finding reopened content: application/json: schema: $ref: '#/components/schemas/FindingDetail' /internal/tenants/{tenantId}/findings/{findingId}/system-clear: post: tags: [FindingsInternal] summary: Apply a trusted system-clear reason operationId: systemClearFinding x-internal: true parameters: - $ref: '#/components/parameters/TenantId' - $ref: '#/components/parameters/FindingId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SystemClearFindingRequest' responses: '200': description: Finding moved into a verified-cleared outcome content: application/json: schema: $ref: '#/components/schemas/FindingDetail' /internal/tenants/{tenantId}/findings/{findingId}/system-reopen: post: tags: [FindingsInternal] summary: Reopen a terminal finding due to trusted recurrence or verification failure operationId: systemReopenFinding x-internal: true parameters: - $ref: '#/components/parameters/TenantId' - $ref: '#/components/parameters/FindingId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SystemReopenFindingRequest' responses: '200': description: Finding reopened by trusted automation content: application/json: schema: $ref: '#/components/schemas/FindingDetail' components: parameters: TenantId: name: tenantId in: path required: true schema: type: integer FindingId: name: findingId in: path required: true schema: type: integer schemas: FindingStatus: type: string enum: - new - acknowledged - triaged - in_progress - reopened - resolved - closed - risk_accepted VerificationState: type: string enum: - pending_verification - verified_cleared - not_applicable ResolveReasonKey: type: string enum: - remediated - no_longer_drifting - permission_granted - permission_removed_from_registry - role_assignment_removed - ga_count_within_threshold CloseReasonKey: type: string enum: - false_positive - duplicate - no_longer_applicable - accepted_risk ReopenReasonKey: type: string enum: - recurred_after_resolution - verification_failed - manual_reassessment TerminalOutcomeKey: type: string enum: - resolved_pending_verification - verified_cleared - closed_false_positive - closed_duplicate - closed_no_longer_applicable - risk_accepted TerminalOutcome: type: object required: - key - label - verification_state - report_bucket properties: key: $ref: '#/components/schemas/TerminalOutcomeKey' label: type: string verification_state: $ref: '#/components/schemas/VerificationState' report_bucket: type: string enum: - remediation_pending_verification - remediation_verified - administrative_closure - accepted_risk governance_state: type: string nullable: true description: Present only when the outcome depends on risk-governance validity. ResolveFindingRequest: type: object required: [reason] properties: reason: type: string enum: [remediated] note: type: string maxLength: 255 nullable: true CloseFindingRequest: type: object required: [reason] properties: reason: type: string enum: - false_positive - duplicate - no_longer_applicable note: type: string maxLength: 255 nullable: true ReopenFindingRequest: type: object required: [reason] properties: reason: $ref: '#/components/schemas/ReopenReasonKey' note: type: string maxLength: 255 nullable: true SystemClearFindingRequest: type: object required: [reason, observed_at] properties: reason: type: string enum: - no_longer_drifting - permission_granted - permission_removed_from_registry - role_assignment_removed - ga_count_within_threshold observed_at: type: string format: date-time operation_run_id: type: integer nullable: true SystemReopenFindingRequest: type: object required: [reason, observed_at] properties: reason: type: string enum: - recurred_after_resolution - verification_failed observed_at: type: string format: date-time operation_run_id: type: integer nullable: true FindingSummary: type: object required: - id - tenant_id - status - severity - terminal_outcome properties: id: type: integer tenant_id: type: integer status: $ref: '#/components/schemas/FindingStatus' severity: type: string resolved_reason: oneOf: - $ref: '#/components/schemas/ResolveReasonKey' - type: 'null' closed_reason: oneOf: - $ref: '#/components/schemas/CloseReasonKey' - type: 'null' terminal_outcome: $ref: '#/components/schemas/TerminalOutcome' FindingDetail: allOf: - $ref: '#/components/schemas/FindingSummary' - type: object properties: resolved_at: type: string format: date-time nullable: true closed_at: type: string format: date-time nullable: true reopened_at: type: string format: date-time nullable: true audit_context: type: object additionalProperties: true description: Logical placeholder for the readable audit/history payload.