TenantAtlas/specs/159-baseline-snapshot-truth/contracts/openapi.yaml
ahmido 8426741068 feat: add baseline snapshot truth guards (#189)
## Summary
- add explicit BaselineSnapshot lifecycle truth with conservative backfill and a shared truth resolver
- block baseline compare from building, incomplete, or superseded snapshots and align workspace/tenant UI truth surfaces with effective snapshot state
- surface artifact truth separately from operation outcome across baseline profile, snapshot, compare, and operation run pages

## Testing
- integrated browser smoke test on the active feature surfaces
- `vendor/bin/sail artisan test --compact tests/Feature/Filament/BaselineSnapshotTruthSurfaceTest.php tests/Feature/Filament/BaselineProfileCompareStartSurfaceTest.php`
- targeted baseline lifecycle and compare guard coverage added in Pest
- `vendor/bin/sail bin pint --dirty --format agent`

## Notes
- Livewire v4 compliance preserved
- no panel provider registration changes were needed; Laravel 12 providers remain in `bootstrap/providers.php`
- global search remains disabled for the affected baseline resources by design
- destructive actions remain confirmation-gated; capture and compare actions keep their existing authorization and confirmation behavior
- no new panel assets were added; existing deploy flow for `filament:assets` is unchanged

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #189
2026-03-23 11:32:00 +00:00

262 lines
7.8 KiB
YAML

openapi: 3.1.0
info:
title: BaselineSnapshot Artifact Truth Operator Contract
version: 1.0.0
summary: Logical operator-action contract for baseline snapshot lifecycle and compare guards
description: |
This contract captures the intended request/response semantics for the operator-facing
capture, compare, and snapshot-truth flows in Spec 159. These are logical contracts for
existing Filament/Livewire-backed actions and read models, not a commitment to public REST endpoints.
servers:
- url: https://tenantpilot.local
tags:
- name: BaselineProfiles
- name: BaselineSnapshots
- name: BaselineCompare
paths:
/workspaces/{workspaceId}/baseline-profiles/{profileId}/captures:
post:
tags: [BaselineProfiles]
summary: Start a baseline capture
description: Starts a baseline capture attempt. The produced snapshot begins in `building` and becomes consumable only if finalized `complete`.
parameters:
- $ref: '#/components/parameters/WorkspaceId'
- $ref: '#/components/parameters/ProfileId'
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [sourceTenantId]
properties:
sourceTenantId:
type: integer
responses:
'202':
description: Capture accepted and queued
content:
application/json:
schema:
type: object
required: [operationRunId, snapshot]
properties:
operationRunId:
type: integer
snapshot:
$ref: '#/components/schemas/BaselineSnapshotTruth'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
/workspaces/{workspaceId}/baseline-profiles/{profileId}/effective-snapshot:
get:
tags: [BaselineProfiles]
summary: Resolve effective current baseline snapshot
description: Returns the latest complete snapshot that is valid as current baseline truth for the profile.
parameters:
- $ref: '#/components/parameters/WorkspaceId'
- $ref: '#/components/parameters/ProfileId'
responses:
'200':
description: Effective current baseline truth resolved
content:
application/json:
schema:
type: object
required: [profileId, effectiveSnapshot]
properties:
profileId:
type: integer
effectiveSnapshot:
oneOf:
- $ref: '#/components/schemas/BaselineSnapshotTruth'
- type: 'null'
latestAttemptedSnapshot:
oneOf:
- $ref: '#/components/schemas/BaselineSnapshotTruth'
- type: 'null'
compareAvailability:
$ref: '#/components/schemas/CompareAvailability'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
/workspaces/{workspaceId}/baseline-snapshots/{snapshotId}:
get:
tags: [BaselineSnapshots]
summary: Read baseline snapshot truth
parameters:
- $ref: '#/components/parameters/WorkspaceId'
- $ref: '#/components/parameters/SnapshotId'
responses:
'200':
description: Snapshot truth returned
content:
application/json:
schema:
$ref: '#/components/schemas/BaselineSnapshotTruth'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
/tenants/{tenantId}/baseline-compares:
post:
tags: [BaselineCompare]
summary: Start baseline compare
description: Starts compare only when the resolved or explicitly selected snapshot is consumable.
parameters:
- $ref: '#/components/parameters/TenantId'
requestBody:
required: false
content:
application/json:
schema:
type: object
properties:
baselineSnapshotId:
type: integer
nullable: true
responses:
'202':
description: Compare accepted and queued
content:
application/json:
schema:
type: object
required: [operationRunId, snapshot]
properties:
operationRunId:
type: integer
snapshot:
$ref: '#/components/schemas/BaselineSnapshotTruth'
'409':
description: Compare blocked because no consumable snapshot is available
content:
application/json:
schema:
$ref: '#/components/schemas/CompareAvailability'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
components:
parameters:
WorkspaceId:
name: workspaceId
in: path
required: true
schema:
type: integer
ProfileId:
name: profileId
in: path
required: true
schema:
type: integer
SnapshotId:
name: snapshotId
in: path
required: true
schema:
type: integer
TenantId:
name: tenantId
in: path
required: true
schema:
type: integer
responses:
Forbidden:
description: Member lacks the required capability
NotFound:
description: Workspace or tenant scope is not entitled, or the record is not visible in that scope
schemas:
BaselineSnapshotTruth:
type: object
required:
- id
- workspaceId
- baselineProfileId
- lifecycleState
- consumable
- capturedAt
properties:
id:
type: integer
workspaceId:
type: integer
baselineProfileId:
type: integer
lifecycleState:
type: string
enum: [building, complete, incomplete, superseded]
consumable:
type: boolean
capturedAt:
type: string
format: date-time
completedAt:
type: string
format: date-time
nullable: true
failedAt:
type: string
format: date-time
nullable: true
supersededAt:
type: string
format: date-time
nullable: true
completionMeta:
type: object
additionalProperties: true
nullable: true
usabilityLabel:
type: string
examples: [Complete, Incomplete, Building, Superseded, Not usable for compare]
reasonCode:
type: string
nullable: true
reasonMessage:
type: string
nullable: true
CompareAvailability:
type: object
required:
- allowed
properties:
allowed:
type: boolean
effectiveSnapshotId:
type: integer
nullable: true
latestAttemptedSnapshotId:
type: integer
nullable: true
reasonCode:
type: string
nullable: true
enum:
- no_consumable_snapshot
- snapshot_building
- snapshot_incomplete
- snapshot_superseded
- invalid_snapshot_selection
reasonMessage:
type: string
nullable: true
nextAction:
type: string
nullable: true
examples:
- Wait for capture completion
- Re-run baseline capture
- Review failed capture