TenantAtlas/specs/255-enforce-finding-creation-invariants/contracts/finding-creation-invariants.contract.yaml
ahmido ab9c36f21e
Some checks failed
Main Confidence / confidence (push) Failing after 59s
Automatische PR: platform-dev → dev (#299)
Automatisch erstellt: Merge `platform-dev` into `dev` (via MCP)

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #299
2026-04-29 12:37:48 +00:00

101 lines
4.5 KiB
YAML

version: 1
kind: finding-creation-invariants
scope:
goal: enforce lifecycle-ready finding creation and recurrence or reopen semantics across the active finding writers only
non_goals:
- repair tooling or backfill runtime surfaces
- new workflow states or new findings lifecycle families
- customer-facing workflow expansion
- compare refresh work
- external support handoff
- broader findings redesign
- silent database-constraint rollout
stop_conditions:
- another shipped finding writer is discovered outside the three confirmed paths
- application-level write enforcement proves insufficient without a migration or DB constraint
- the only available implementation shape is a new generic invariant framework
active_writer_families:
baseline_compare:
owner_files:
- apps/platform/app/Jobs/CompareBaselineToTenantJob.php
identity:
canonical_key: recurrence_key
fingerprint_contract: fingerprint equals recurrence_key
observation_boundary:
duplicate_guard: current_operation_run_id prevents double counting the same compare run
entra_admin_roles:
owner_files:
- apps/platform/app/Services/EntraAdminRoles/EntraAdminRolesFindingGenerator.php
identity:
canonical_key: existing role-assignment or aggregate fingerprint
observation_boundary:
duplicate_guard: later observedAt advances seen history
permission_posture:
owner_files:
- apps/platform/app/Services/PermissionPosture/PermissionPostureFindingGenerator.php
identity:
canonical_key: existing permission or error fingerprint
observation_boundary:
duplicate_guard: later observedAt advances seen history
shared_lifecycle_contract:
model:
owner_file: apps/platform/app/Models/Finding.php
invariants:
- workspace_id and tenant_id remain required ownership anchors
- no new status or reason-code family is introduced
reopen_service:
owner_file: apps/platform/app/Services/Findings/FindingWorkflowService.php
requirement:
- terminal findings reopen only through reopenBySystem
- reopened_at is set
- resolved and closed markers clear according to current service behavior
- sla_days and due_at are recalculated from reopenedAt
- existing audit and alert side effects are preserved
lifecycle_invariants:
create:
required_fields:
- status is new
- first_seen_at equals observedAt
- last_seen_at equals observedAt
- times_seen equals 1
- sla_days is initialized when the current severity policy returns a value
- due_at is initialized when the current severity policy requires due-state truth
contextual_fields:
- current_operation_run_id remains populated where the current writer already sets it
refresh_existing:
required_behavior:
- the same canonical finding identity is reused
- missing first_seen_at, last_seen_at, and times_seen are repaired inline
- missing sla_days or due_at covered by this slice are repaired inline without a second-pass repair tool
- already-valid lifecycle fields are not reset unnecessarily
reopen:
required_behavior:
- the same canonical finding identity is reopened, not duplicated
- resolved_at and resolved_reason clear on reopen
- first_seen_at is retained
- last_seen_at and times_seen advance according to the family observation rule
downstream_regression_consumers:
findings_surfaces:
owner_files:
- apps/platform/app/Filament/Resources/FindingResource.php
- apps/platform/app/Filament/Resources/FindingResource/Pages/ListFindings.php
- apps/platform/app/Filament/Pages/Findings/MyFindingsInbox.php
- apps/platform/app/Filament/Pages/Findings/FindingsIntakeQueue.php
expectation:
- no design change is required; these surfaces should continue to read truthful due_at and reopened_at data from the same Finding records
validation_expectations:
required_feature_proof:
- baseline compare proves create readiness, same-run retry protection, reopened reuse, and inline repair of incomplete lifecycle fields
- Entra admin roles proves create readiness, repeated observation, reopened reuse, and inline repair of incomplete lifecycle fields
- permission posture proves create readiness, repeated observation, reopened reuse, and inline repair of incomplete lifecycle fields
excluded_lanes:
- browser
- heavy-governance
migration_posture:
- no new migration or schema artifact is allowed in this slice