TenantAtlas/specs/219-finding-ownership-semantics/contracts/finding-responsibility.openapi.yaml
ahmido c86b399b43
Some checks failed
Main Confidence / confidence (push) Failing after 53s
feat(219): Finding ownership semantics + LEAN-001 constitution + backup_set unification (#256)
## Summary

This PR delivers three related improvements:

### 1. Finding Ownership Semantics (Spec 219)
- Add responsibility/accountability labels to findings and finding exceptions
- `owner_user_id` = accountable party (governance owner)
- `assignee_user_id` = responsible party (technical implementer)
- Expose Assign/Reassign actions in FindingResource with audit logging
- Add ownership columns and filters to finding list
- Propagate owner from finding to exception on creation
- Tests: ownership semantics, assignment audit, workflow actions

### 2. Constitution v2.7.0 — LEAN-001 Pre-Production Lean Doctrine
- New principle forbidding legacy aliases, migration shims, dual-write logic, and compatibility fixtures in a pre-production codebase
- AI-agent 4-question verification gate before adding any compatibility path
- Review rule: compatibility shims without answering the gate questions = merge blocker
- Exit condition: LEAN-001 expires at first production deployment
- Spec template: added default "Compatibility posture" block
- Agent instructions: added "Pre-production compatibility check" section

### 3. Backup Set Operation Type Unification
- Unified `backup_set.add_policies` and `backup_set.remove_policies` into single canonical `backup_set.update`
- Removed all legacy aliases, constants, and test fixtures
- Added lifecycle coverage for `backup_set.update` in config
- Updated all 14+ test files referencing legacy types

### Spec Artifacts
- `specs/219-finding-ownership-semantics/` — full spec, plan, tasks, research, data model, contracts, checklist

### Tests
- All affected tests pass (OperationCatalog, backup set, finding workflow, ownership semantics)

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #256
2026-04-20 17:54:33 +00:00

248 lines
7.4 KiB
YAML

openapi: 3.1.0
info:
title: TenantPilot Internal Finding Responsibility Contract
version: 1.0.0
description: |
Internal review contract for Spec 219.
These are operator-facing Filament surfaces, not public API endpoints. The document exists so
the feature has an explicit, reviewable contract under specs/.../contracts/.
paths:
/admin/t/{tenant}/findings:
get:
summary: Tenant findings list with explicit responsibility semantics
parameters:
- $ref: '#/components/parameters/TenantPathParam'
responses:
'200':
description: Findings list rendered
content:
application/json:
schema:
$ref: '#/components/schemas/FindingListSurface'
/admin/t/{tenant}/findings/{finding}:
get:
summary: Finding detail with owner, assignee, and optional exception-owner context
parameters:
- $ref: '#/components/parameters/TenantPathParam'
- $ref: '#/components/parameters/FindingPathParam'
responses:
'200':
description: Finding detail rendered
content:
application/json:
schema:
$ref: '#/components/schemas/FindingDetailSurface'
/admin/t/{tenant}/findings/{finding}/responsibility:
post:
summary: Update finding owner and assignee semantics
description: Conceptual responsibility-update contract implemented by Filament action endpoints.
parameters:
- $ref: '#/components/parameters/TenantPathParam'
- $ref: '#/components/parameters/FindingPathParam'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ResponsibilityUpdateRequest'
responses:
'200':
description: Responsibility updated
content:
application/json:
schema:
$ref: '#/components/schemas/ResponsibilityUpdateResult'
'403':
description: Actor is an in-scope tenant member but lacks assignment capability
'404':
description: Tenant or finding is outside the actor scope
/admin/t/{tenant}/findings/{finding}/exception-request:
post:
summary: Request exception with explicitly separate exception owner
description: Conceptual exception-request contract implemented by Filament action endpoints.
parameters:
- $ref: '#/components/parameters/TenantPathParam'
- $ref: '#/components/parameters/FindingPathParam'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionRequestInput'
responses:
'200':
description: Exception request accepted
content:
application/json:
schema:
$ref: '#/components/schemas/ExceptionOwnershipBoundaryResult'
components:
parameters:
TenantPathParam:
name: tenant
in: path
required: true
schema:
type: string
description: Tenant route identifier for tenant-scoped findings surfaces.
FindingPathParam:
name: finding
in: path
required: true
schema:
type: integer
description: Tenant-owned finding identifier.
schemas:
UserReference:
type: object
additionalProperties: false
required:
- id
- display_name
properties:
id:
type: integer
display_name:
type: string
ResponsibilityState:
type: string
description: Uses internal slugs for API and test contracts. The operator-facing UI label for `orphaned_accountability` is `orphaned accountability`.
enum:
- orphaned_accountability
- owned_unassigned
- assigned
FindingResponsibilitySummary:
type: object
additionalProperties: false
required:
- finding_id
- workflow_status
- responsibility_state
properties:
finding_id:
type: integer
workflow_status:
type: string
owner:
allOf:
- $ref: '#/components/schemas/UserReference'
nullable: true
assignee:
allOf:
- $ref: '#/components/schemas/UserReference'
nullable: true
responsibility_state:
$ref: '#/components/schemas/ResponsibilityState'
accountability_gap:
type: boolean
exception_owner:
allOf:
- $ref: '#/components/schemas/UserReference'
nullable: true
description: Present only when a finding exception exists or is shown in current context.
FindingListSurface:
type: object
additionalProperties: false
required:
- surface
- collection_route
- primary_inspect_model
- items
properties:
surface:
const: tenant_findings_list
collection_route:
const: /admin/t/{tenant}/findings
primary_inspect_model:
const: finding
items:
type: array
items:
$ref: '#/components/schemas/FindingResponsibilitySummary'
FindingDetailSurface:
allOf:
- $ref: '#/components/schemas/FindingResponsibilitySummary'
- type: object
additionalProperties: false
required:
- surface
- detail_route
properties:
surface:
const: finding_detail
detail_route:
const: /admin/t/{tenant}/findings/{finding}
ResponsibilityUpdateRequest:
type: object
additionalProperties: false
properties:
owner_user_id:
type: integer
nullable: true
description: Accountable owner for the finding outcome.
assignee_user_id:
type: integer
nullable: true
description: Active remediation assignee for the finding.
ResponsibilityUpdateResult:
type: object
additionalProperties: false
required:
- change_classification
- responsibility
properties:
change_classification:
type: string
description: Uses explicit slugs for single-role clears and `owner_and_assignee` whenever both fields change in one update, including mixed set/clear combinations.
enum:
- owner_only
- assignee_only
- owner_and_assignee
- clear_owner
- clear_assignee
responsibility:
$ref: '#/components/schemas/FindingResponsibilitySummary'
ExceptionRequestInput:
type: object
additionalProperties: false
required:
- owner_user_id
- request_reason
- review_due_at
properties:
owner_user_id:
type: integer
description: Owner of the exception artifact, not the finding owner.
request_reason:
type: string
review_due_at:
type: string
format: date-time
expires_at:
type: string
format: date-time
nullable: true
ExceptionOwnershipBoundaryResult:
type: object
additionalProperties: false
required:
- finding_owner_preserved
- exception_owner
properties:
finding_owner_preserved:
type: boolean
const: true
exception_owner:
$ref: '#/components/schemas/UserReference'