Files
ss-tools/specs/047-dashboard-scenario-analytics/contracts/openapi.yaml

229 lines
13 KiB
YAML

openapi: 3.1.0
info:
title: Investigation Queue & Scenario Analytics API
version: 0.3.0
description: Analyst-opened agentic investigation cases over deterministic scenario health, trends and recurring failures.
paths:
/api/internal/investigation-signals:
post:
operationId: investigations.ingestSignal
summary: Idempotently ingest a deterministic producer signal into the Investigation Queue
description: Internal producer route. Ingestion creates/updates Queue/Episode only and never starts an agent chat or AgentRun.
security: [{ serviceAndUser: [] }]
requestBody:
required: true
content:
application/json:
schema: { $ref: "#/components/schemas/InvestigationSignal" }
responses:
"202": { description: Signal accepted; Queue item created or updated deterministically, content: { application/json: { schema: { $ref: "#/components/schemas/InvestigationQueueItem" } } } }
"409": { description: Signal identity was reused with non-canonical content }
/api/investigation-queue:
get:
operationId: investigations.listQueue
summary: List deduplicated attention items; listing never starts an agent run
security: [{ bearerAuth: [] }]
parameters:
- { name: state, in: query, schema: { type: string, enum: [new, acknowledged, case_opened, suppressed, resolved] } }
- { name: scenario_id, in: query, schema: { type: string } }
- { name: severity, in: query, schema: { type: string, enum: [info, warning, critical] } }
responses:
"200":
description: InvestigationQueueItem[]
content: { application/json: { schema: { type: array, items: { $ref: "#/components/schemas/InvestigationQueueItem" } } } }
/api/investigation-queue/{queue_item_id}/open-case:
post:
operationId: investigations.openCase
summary: Explicitly open a persistent InvestigationCase and its agent thread
security: [{ bearerAuth: [] }]
parameters: [{ name: queue_item_id, in: path, required: true, schema: { type: string, format: uuid } }]
responses:
"201":
description: Case opened
content: { application/json: { schema: { $ref: "#/components/schemas/InvestigationCase" } } }
"200":
description: Existing case for the active queue item
content: { application/json: { schema: { $ref: "#/components/schemas/InvestigationCase" } } }
"403": { description: Requires source-object and evidence access }
"409": { description: Queue item is suppressed/resolved or has incompatible case state }
/api/investigation-cases/{case_id}:
get:
operationId: investigations.getCase
summary: Get persistent case, evidence, compact triage and action timeline
security: [{ bearerAuth: [] }]
parameters: [{ name: case_id, in: path, required: true, schema: { type: string, format: uuid } }]
responses:
"200": { description: InvestigationCase, content: { application/json: { schema: { $ref: "#/components/schemas/InvestigationCase" } } } }
"403": { description: Requires source-object and evidence access }
"404": { description: Not found }
/api/investigation-cases/{case_id}/disposition:
post:
operationId: investigations.setDisposition
summary: Record an analyst-confirmed case disposition and update compact triage projection
security: [{ bearerAuth: [] }]
parameters: [{ name: case_id, in: path, required: true, schema: { type: string, format: uuid } }]
requestBody:
required: true
content:
application/json:
schema: { $ref: "#/components/schemas/CaseDispositionRequest" }
responses:
"200": { description: Updated case and audited TriageRecord projection, content: { application/json: { schema: { $ref: "#/components/schemas/InvestigationCase" } } } }
"403": { description: Requires scenario-result:triage and object access }
"409": { description: Stale decision_version or terminal-case conflict }
"422": { description: Invalid state/disposition combination }
/api/scenarios/{scenario_id}/health:
get:
operationId: analytics.health
summary: Contextual deterministic health feeding 042 badge
security: [{ bearerAuth: [] }]
parameters:
- { name: scenario_id, in: path, required: true, schema: { type: string } }
- { name: environment_class, in: query, schema: { type: string } }
- { name: context_key, in: query, schema: { type: string } }
responses:
"200": { description: ScenarioHealth, content: { application/json: { schema: { $ref: "#/components/schemas/ScenarioHealth" } } } }
/api/scenarios/{scenario_id}/trends:
get:
operationId: analytics.trends
summary: Deterministic success and classified/disposition trend series
security: [{ bearerAuth: [] }]
parameters: [{ name: scenario_id, in: path, required: true, schema: { type: string } }]
responses:
"200": { description: Trends, content: { application/json: { schema: { $ref: "#/components/schemas/Trends" } } } }
/api/scenarios/{scenario_id}/recurring-failures:
get:
operationId: analytics.recurring
summary: Compatibility-scoped recurring groups and episodes
security: [{ bearerAuth: [] }]
parameters: [{ name: scenario_id, in: path, required: true, schema: { type: string } }]
responses:
"200": { description: "RecurringFailureGroup[]", content: { application/json: { schema: { type: array, items: { $ref: "#/components/schemas/RecurringFailureGroup" } } } } }
components:
securitySchemes:
bearerAuth: { type: http, scheme: bearer }
serviceAndUser: { type: http, scheme: bearer, description: "Trusted producer service with originating user/provenance context" }
schemas:
InvestigationQueueItem:
type: object
required: [id, source_type, severity, state, count, first_seen_at, last_seen_at]
properties:
id: { type: string, format: uuid }
source_type: { type: string, enum: [scenario_run, staleness_signal, baseline_immutability, load_finding, automation_failure] }
scenario_id: { type: [string, 'null'] }
run_id: { type: [string, 'null'], format: uuid }
logical_step_id: { type: [string, 'null'], format: uuid }
severity: { type: string, enum: [info, warning, critical] }
fingerprint: { type: [string, 'null'] }
active_episode_id: { type: [string, 'null'], format: uuid }
evidence_summary: { type: object, additionalProperties: true }
target_snapshot: { type: object, additionalProperties: true }
suggested_next_action: { type: [string, 'null'] }
state: { type: string, enum: [new, acknowledged, case_opened, suppressed, resolved] }
count: { type: integer, minimum: 1 }
first_seen_at: { type: string, format: date-time }
last_seen_at: { type: string, format: date-time }
case_id: { type: [string, 'null'], format: uuid }
InvestigationSignal:
type: object
required: [source_type, source_id, severity, evidence_refs, occurred_at]
properties:
source_type: { type: string, enum: [scenario_run, staleness_signal, baseline_immutability, load_finding, automation_failure] }
source_id: { type: string }
scenario_id: { type: [string, 'null'] }
run_id: { type: [string, 'null'], format: uuid }
logical_step_id: { type: [string, 'null'], format: uuid }
severity: { type: string, enum: [info, warning, critical] }
canonical_fingerprint: { type: [string, 'null'] }
evidence_refs: { type: array, items: { type: string, format: uuid } }
target_snapshot: { type: [object, 'null'], additionalProperties: true }
execution_principal_fingerprint: { type: [string, 'null'] }
occurred_at: { type: string, format: date-time }
InvestigationCase:
type: object
required: [id, queue_item_id, status, source_snapshot, evidence_snapshot, owner_actor_id, agent_thread_id, opened_at]
properties:
id: { type: string, format: uuid }
queue_item_id: { type: string, format: uuid }
status: { type: string, enum: [open, investigating, awaiting_approval, awaiting_external_change, verifying, resolved, accepted, reopened] }
source_snapshot: { type: object, additionalProperties: true }
evidence_snapshot: { type: object, additionalProperties: true }
owner_actor_id: { type: string }
agent_thread_id: { type: string }
opened_at: { type: string, format: date-time }
resolved_at: { type: [string, 'null'], format: date-time }
final_disposition: { type: [string, 'null'], enum: [fixed, accepted_risk, duplicate, wont_fix, false_positive] }
resolution_summary: { type: [string, 'null'] }
triage: { $ref: "#/components/schemas/TriageRecord" }
actions: { type: array, items: { $ref: "#/components/schemas/AgentAction" } }
CaseDispositionRequest:
type: object
required: [decision_version, investigation_status]
properties:
decision_version: { type: integer, minimum: 1 }
investigation_status: { type: string, enum: [new, investigating, resolved] }
classification: { type: string, enum: [product_regression, data_regression, baseline_stale, scenario_bug, infrastructure_failure, not_confirmed] }
resolution: { type: string, enum: [fixed, accepted_risk, duplicate, wont_fix, false_positive] }
comment: { type: string, maxLength: 4000 }
verification_evidence_refs: { type: array, items: { type: string, format: uuid }, description: "Required to transition a case to resolved" }
acceptance_rationale: { type: string, maxLength: 4000, description: "Required for accepted-risk/wont-fix terminal acceptance" }
TriageRecord:
type: object
properties:
investigation_status: { type: string }
classification: { type: [string, 'null'] }
resolution: { type: [string, 'null'] }
comment: { type: [string, 'null'] }
decision_version: { type: integer }
actor_id: { type: string }
AgentAction:
type: object
required: [id, intent, risk_class, policy_decision, status]
properties:
id: { type: string, format: uuid }
intent: { type: string }
risk_class: { type: string, enum: [read, diagnostic_run, controlled_test_data_mutation, draft_write, scenario_revision_write, activate_current_revision, baseline_approval, automation_policy_write, prod_mutation] }
policy_decision: { type: string, enum: [delegated, approval_required, denied] }
status: { type: string, enum: [planned, running, completed, failed, awaiting_reconciliation] }
evidence_refs: { type: array, items: { type: string, format: uuid } }
approval_gate_id: { type: [string, 'null'], format: uuid }
ScenarioHealth:
type: object
required: [scenario_id, overall_attention, generated_at, confidence]
properties:
scenario_id: { type: string }
environment_class: { type: string }
context_key: { type: string, description: "044 AnalyticsContextKey" }
product_health: { type: string, enum: [healthy, attention, unknown] }
scenario_test_health: { type: string, enum: [healthy, attention, unknown] }
infrastructure_health: { type: string, enum: [healthy, attention, unknown] }
agent_evaluation_health: { type: string, enum: [healthy, attention, unknown] }
overall_attention: { type: string, enum: [healthy, attention, unknown] }
success_rate: { type: number }
flaky_ratio: { type: number }
infra_failure_ratio: { type: number }
inconclusive_ratio: { type: number }
agent_disagreement_ratio: { type: number }
low_confidence_ratio: { type: number }
model_instability_ratio: { type: number }
generated_at: { type: string, format: date-time }
confidence: { type: string, enum: [insufficient_history, low, high] }
Trends:
type: object
required: [generated_at, success_rate_series, disposition_distribution]
properties:
generated_at: { type: string, format: date-time }
success_rate_series: { type: array, items: { type: object } }
disposition_distribution: { type: object, additionalProperties: { type: integer } }
RecurringFailureGroup:
type: object
required: [id, fingerprint, compatibility_family, count, first_occurred_at, last_occurred_at, episodes]
properties:
id: { type: string, format: uuid }
fingerprint: { type: string, description: "logical_step_id + error_code + normalized_error_signature + assertion_kind + affected_ref" }
compatibility_family: { type: string }
count: { type: integer }
first_occurred_at: { type: string, format: date-time }
last_occurred_at: { type: string, format: date-time }
episodes: { type: array, items: { type: object, properties: { id: { type: string, format: uuid }, opened_at: { type: string, format: date-time }, resolved_at: { type: [string, 'null'], format: date-time } } } }