TenantAtlas/specs/219-finding-ownership-semantics/data-model.md
Ahmed Darrazi 1741b22203 docs: amend constitution to v2.7.0 (LEAN-001 pre-production lean doctrine)
- Add LEAN-001 to constitution after BIAS-001: forbids legacy aliases,
  migration shims, dual-write logic, and compatibility fixtures in a
  pre-production codebase
- Add compatibility posture default block to spec template
- Add pre-production compatibility check to agent instructions
- Unify backup_set operation type to canonical backup_set.update
- Remove all legacy backup_set.add_policies/remove_policies references
- Add finding ownership semantics (responsibility/accountability labels)
- Clean up roadmap.md and spec-candidates.md
2026-04-20 19:53:04 +02:00

5.6 KiB

Data Model: Finding Ownership Semantics Clarification

Date: 2026-04-20
Branch: 219-finding-ownership-semantics

Overview

This feature introduces no new persisted entities. It clarifies responsibility semantics over existing finding and finding-exception records and adds one derived responsibility-state projection for operator-facing surfaces.

Entity: Finding

Represents: A tenant-owned operational governance finding that moves through the findings workflow and may carry both accountable ownership and active remediation assignment.

Key Fields

Field Type Required Notes
id bigint yes Primary key
workspace_id bigint yes Derived tenant ownership boundary
tenant_id bigint yes Tenant isolation boundary
status string yes Existing findings lifecycle state
severity string yes Existing severity dimension
owner_user_id bigint nullable no Accountable person for the finding outcome
assignee_user_id bigint nullable no Active remediation executor / coordinator
due_at datetime nullable no Existing SLA/follow-up deadline
resolved_reason string nullable no Existing closure context
closed_reason string nullable no Existing closure/governance context

Relationships

Relationship Target Cardinality Purpose
tenant() Tenant belongsTo Tenant ownership and authorization
ownerUser() User belongsTo Accountable owner
assigneeUser() User belongsTo Active remediation assignee
findingException() FindingException hasOne Optional exception artifact for accepted-risk governance

Validation Rules

  • owner_user_id MAY be null.
  • assignee_user_id MAY be null.
  • If present, either user ID MUST reference a current member of the active tenant.
  • Responsibility changes are allowed only on open findings, matching the current FindingWorkflowService::assign() rule.

Entity: FindingException

Represents: A tenant-owned exception artifact attached to a finding when governance coverage is requested or granted.

Key Fields

Field Type Required Notes
id bigint yes Primary key
finding_id bigint yes Owning finding
tenant_id bigint yes Tenant isolation boundary
owner_user_id bigint nullable no Accountable owner of the exception artifact, not of the finding itself
status string yes Existing exception lifecycle state
current_validity_state string nullable no Existing governance-validity dimension
request_reason text yes Existing request context

Relationships

Relationship Target Cardinality Purpose
finding() Finding belongsTo Parent finding context
owner() User belongsTo Exception artifact owner

Validation Rules

  • Exception-owner selection continues to use current tenant-member validation.
  • Exception ownership MUST remain semantically distinct from finding ownership on all mixed-context surfaces.

Derived Projection: ResponsibilityState

Represents: An operator-facing derived state computed from owner_user_id and assignee_user_id without new persistence.

Naming convention:

  • Operator-facing UI label: orphaned accountability
  • Internal derived-state and contract slug: orphaned_accountability

Derived Values

Derived State Rule Operator Meaning
orphaned_accountability owner_user_id == null No accountable owner is set. This remains true even if an assignee exists.
owned_unassigned owner_user_id != null && assignee_user_id == null Someone owns the outcome, but active remediation work is not assigned.
assigned owner_user_id != null && assignee_user_id != null Accountability and active remediation assignment are both set.

Rendering Notes

  • If owner and assignee are the same user, the state remains assigned; the UI should show both roles satisfied without implying a data problem.
  • If both are null, the finding still uses the slug orphaned_accountability and the visible label orphaned accountability.
  • If assignee is present but owner is null, the finding remains orphaned_accountability; the UI may also show that remediation is assigned without accountable ownership.

Mutation Contract: ResponsibilityUpdate

Represents: The input/output contract of the existing assignment action.

Input Shape

Field Type Required Notes
owner_user_id bigint nullable no Set, change, or clear finding owner
assignee_user_id bigint nullable no Set, change, or clear finding assignee

Behavioral Rules

  • The existing FindingWorkflowService::assign() method remains the mutation boundary.
  • The service MUST continue to write both fields explicitly to the finding.
  • Operator feedback and audit-facing wording should classify the result as owner_only, assignee_only, clear_owner, clear_assignee, or owner_and_assignee when both fields change in one update.

State and Lifecycle Impact

This feature does not add a new lifecycle family. It overlays responsibility semantics on top of existing findings lifecycle states.

Existing Lifecycle State Responsibility Impact
new, triaged, in_progress, reopened, acknowledged Responsibility state is actionable and visible by default
resolved, closed Responsibility remains historical context only
risk_accepted Responsibility remains visible, but exception-owner context may also appear and must remain separate