## Summary - replace the baseline snapshot detail page with a structured summary-first rendering flow - add a presenter plus renderer registry with RBAC, compliance, and fallback renderers - add grouped policy-type browsing, fidelity and gap badges, and workspace authorization coverage - add Feature 130 spec, plan, contract, research, quickstart, and completed task artifacts ## Testing - focused Pest coverage was added for structured rendering, fallback behavior, degraded states, authorization, presenter logic, renderer resolution, and badge mapping - I did not rerun the full validation suite in this final PR step ## Notes - base branch: `dev` - feature branch: `130-structured-snapshot-rendering` Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #158
272 lines
7.2 KiB
YAML
272 lines
7.2 KiB
YAML
openapi: 3.1.0
|
|
info:
|
|
title: Baseline Snapshot Structured Rendering Contract
|
|
version: 1.0.0
|
|
description: >-
|
|
Behavioral contract for the workspace-scoped Baseline Snapshot detail surface
|
|
after Spec 130. These are HTML/admin-panel endpoints, but the response shape
|
|
is modeled here so summary-first rendering, grouped-browser behavior, and
|
|
authorization semantics stay explicit.
|
|
servers:
|
|
- url: https://tenantpilot.test
|
|
paths:
|
|
/admin/baseline-snapshots:
|
|
get:
|
|
summary: Open the workspace-scoped baseline snapshot list
|
|
operationId: listBaselineSnapshots
|
|
tags:
|
|
- Baseline Snapshot Rendering
|
|
responses:
|
|
'200':
|
|
description: Snapshot list rendered for an authenticated actor entitled to the active workspace scope
|
|
'302':
|
|
description: Redirect to workspace chooser because no workspace is selected
|
|
headers:
|
|
Location:
|
|
schema:
|
|
type: string
|
|
enum:
|
|
- /admin/choose-workspace
|
|
'403':
|
|
description: Actor is in the active workspace scope but lacks the baseline-view capability required for snapshot list inspection
|
|
'404':
|
|
description: Actor is not entitled to the admin workspace plane or active workspace scope
|
|
/admin/baseline-snapshots/{snapshot}:
|
|
get:
|
|
summary: Open the structured baseline snapshot detail page
|
|
operationId: openBaselineSnapshotDetail
|
|
tags:
|
|
- Baseline Snapshot Rendering
|
|
parameters:
|
|
- name: snapshot
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
description: Workspace-owned baseline snapshot identifier
|
|
responses:
|
|
'200':
|
|
description: Structured snapshot detail rendered with metadata, summary, groups, and secondary technical detail
|
|
content:
|
|
text/html:
|
|
schema:
|
|
$ref: '#/components/schemas/BaselineSnapshotDetailPage'
|
|
'302':
|
|
description: Redirect to workspace chooser because no workspace is selected
|
|
headers:
|
|
Location:
|
|
schema:
|
|
type: string
|
|
enum:
|
|
- /admin/choose-workspace
|
|
'403':
|
|
description: Actor is in the active workspace scope but lacks the baseline-view capability required for protected detail rendering
|
|
'404':
|
|
description: Actor is not entitled to the workspace scope or the snapshot is outside the active workspace boundary
|
|
components:
|
|
schemas:
|
|
BaselineSnapshotDetailPage:
|
|
type: object
|
|
required:
|
|
- page
|
|
- snapshot
|
|
- summaryRows
|
|
- groups
|
|
properties:
|
|
page:
|
|
type: string
|
|
const: baseline-snapshot-detail
|
|
snapshot:
|
|
$ref: '#/components/schemas/SnapshotMeta'
|
|
summaryRows:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/SnapshotSummaryRow'
|
|
groups:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/SnapshotGroup'
|
|
technicalDetail:
|
|
description: Optional secondary disclosure shown only when technical payload inspection is retained and authorized.
|
|
$ref: '#/components/schemas/TechnicalDetailDisclosure'
|
|
SnapshotMeta:
|
|
type: object
|
|
required:
|
|
- snapshotId
|
|
- capturedAt
|
|
- overallFidelity
|
|
- overallGapCount
|
|
properties:
|
|
snapshotId:
|
|
type: integer
|
|
baselineProfileName:
|
|
type:
|
|
- string
|
|
- 'null'
|
|
capturedAt:
|
|
type:
|
|
- string
|
|
- 'null'
|
|
format: date-time
|
|
snapshotIdentityHash:
|
|
type:
|
|
- string
|
|
- 'null'
|
|
overallFidelity:
|
|
$ref: '#/components/schemas/FidelityState'
|
|
overallGapCount:
|
|
type: integer
|
|
SnapshotSummaryRow:
|
|
type: object
|
|
required:
|
|
- policyType
|
|
- label
|
|
- itemCount
|
|
- fidelity
|
|
- gapCount
|
|
properties:
|
|
policyType:
|
|
type: string
|
|
label:
|
|
type: string
|
|
itemCount:
|
|
type: integer
|
|
fidelity:
|
|
$ref: '#/components/schemas/FidelityState'
|
|
gapCount:
|
|
type: integer
|
|
capturedAt:
|
|
type:
|
|
- string
|
|
- 'null'
|
|
format: date-time
|
|
coverageHint:
|
|
type:
|
|
- string
|
|
- 'null'
|
|
SnapshotGroup:
|
|
type: object
|
|
required:
|
|
- policyType
|
|
- label
|
|
- itemCount
|
|
- fidelity
|
|
- gapSummary
|
|
- initiallyCollapsed
|
|
- items
|
|
properties:
|
|
policyType:
|
|
type: string
|
|
label:
|
|
type: string
|
|
itemCount:
|
|
type: integer
|
|
fidelity:
|
|
$ref: '#/components/schemas/FidelityState'
|
|
gapSummary:
|
|
$ref: '#/components/schemas/GapSummary'
|
|
initiallyCollapsed:
|
|
type: boolean
|
|
const: true
|
|
renderingError:
|
|
type:
|
|
- string
|
|
- 'null'
|
|
items:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/SnapshotItem'
|
|
SnapshotItem:
|
|
type: object
|
|
required:
|
|
- label
|
|
- typeLabel
|
|
- identityHint
|
|
- referenceStatus
|
|
- fidelity
|
|
- gapSummary
|
|
- structuredAttributes
|
|
properties:
|
|
label:
|
|
type: string
|
|
typeLabel:
|
|
type: string
|
|
identityHint:
|
|
type: string
|
|
referenceStatus:
|
|
type: string
|
|
fidelity:
|
|
$ref: '#/components/schemas/FidelityState'
|
|
gapSummary:
|
|
$ref: '#/components/schemas/GapSummary'
|
|
observedAt:
|
|
type:
|
|
- string
|
|
- 'null'
|
|
format: date-time
|
|
sourceReference:
|
|
type:
|
|
- string
|
|
- 'null'
|
|
structuredAttributes:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/StructuredAttribute'
|
|
StructuredAttribute:
|
|
type: object
|
|
required:
|
|
- label
|
|
- value
|
|
- priority
|
|
properties:
|
|
label:
|
|
type: string
|
|
value:
|
|
oneOf:
|
|
- type: string
|
|
- type: number
|
|
- type: integer
|
|
- type: boolean
|
|
priority:
|
|
type: string
|
|
enum:
|
|
- primary
|
|
- secondary
|
|
GapSummary:
|
|
type: object
|
|
required:
|
|
- count
|
|
- hasGaps
|
|
- messages
|
|
properties:
|
|
count:
|
|
type: integer
|
|
hasGaps:
|
|
type: boolean
|
|
messages:
|
|
type: array
|
|
items:
|
|
type: string
|
|
TechnicalDetailDisclosure:
|
|
type: object
|
|
required:
|
|
- label
|
|
- defaultCollapsed
|
|
properties:
|
|
label:
|
|
type: string
|
|
const: Technical detail
|
|
defaultCollapsed:
|
|
type: boolean
|
|
const: true
|
|
summaryPayloadAvailable:
|
|
type: boolean
|
|
groupPayloadsAvailable:
|
|
type: boolean
|
|
FidelityState:
|
|
type: string
|
|
enum:
|
|
- full
|
|
- partial
|
|
- reference_only
|
|
- unsupported |