{"openapi":"3.1.0","info":{"title":"SecureFlow API","version":"0.1.13"},"paths":{"/api/v1/scenarios":{"get":{"tags":["scenarios"],"summary":"List Scenarios","operationId":"list_scenarios_api_v1_scenarios_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScenarioListResponse"}}}}}},"post":{"tags":["scenarios"],"summary":"Create Scenario","operationId":"create_scenario_api_v1_scenarios_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScenarioWriteBody"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScenarioDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/scenarios/{scenario_id}":{"get":{"tags":["scenarios"],"summary":"Get Scenario","operationId":"get_scenario_api_v1_scenarios__scenario_id__get","parameters":[{"name":"scenario_id","in":"path","required":true,"schema":{"type":"string","title":"Scenario Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScenarioDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["scenarios"],"summary":"Replace Scenario","operationId":"replace_scenario_api_v1_scenarios__scenario_id__put","parameters":[{"name":"scenario_id","in":"path","required":true,"schema":{"type":"string","title":"Scenario Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScenarioWriteBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScenarioDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["scenarios"],"summary":"Delete Scenario","operationId":"delete_scenario_api_v1_scenarios__scenario_id__delete","parameters":[{"name":"scenario_id","in":"path","required":true,"schema":{"type":"string","title":"Scenario Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/system/status":{"get":{"tags":["system"],"summary":"System Status","description":"Aggregated runtime overview for the operator dashboard.","operationId":"system_status_api_v1_system_status_get","parameters":[{"name":"X-SecureFlow-Site-Id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional tenancy partition key. When present and valid, L4 uses configs/sites/<site_id>/site-config.yaml to resolve the system-status default_autonomy_rung.","title":"X-Secureflow-Site-Id"},"description":"Optional tenancy partition key. When present and valid, L4 uses configs/sites/<site_id>/site-config.yaml to resolve the system-status default_autonomy_rung."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SystemStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/system-event-summary":{"get":{"tags":["system"],"summary":"System Event Summary","description":"Aggregate ring-buffer counts + newest timestamps for the L7 dashboard.\n\nReturns ``200`` whenever the L4 service itself is healthy — individual\nengine endpoints degrade to ``null`` on per-key failure (engine down,\ntimeout, malformed payload). When the engine URL is not configured at\nall, every key is ``null`` and the response is still ``200``: the L7\ndashboard tile treats null as the red (\"endpoint returned null\") state.","operationId":"system_event_summary_api_v1_system_event_summary_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SystemEventSummaryResponse"}}}}}}},"/api/v1/edge/devices/enrolled":{"get":{"tags":["edge"],"summary":"List Enrolled Edge Devices","description":"List the ADR-022-enrolled edge nodes with their last-seen + activity state.\n\nSurfaces the per-Jetson enrollment view that wave-44 (BLK-031) landed so\nthe operator UI can show which edge nodes are configured + their recent\nactivity (last MQTT publish, last action dispatched, last shadow-mode\ndecision, last incident, and the active vision-config channel pins).\n\n**Read-only at H1.** Mutations happen through the ADR-022 enrollment\nhandshake (`services/edge-agent` + `scripts/release/jetson_register.py`),\nnever via this L4 surface.\n\n**Server-to-server only.** This endpoint is intentionally NOT on the L7\nBFF allowlist (`frontend/src/lib/l4-bff-allowlist.ts`) — per ADR-004 +\nCLAUDE.md §5, widening the BFF allowlist needs a security review. If the\nUI needs a derived projection, expose it via the existing `edge-devices`\nBFF segment which already gates on the L4 API key.\n\nReturns `[]` (not 404) when the enrollment state is unconfigured or empty\nso the caller can distinguish \"no devices yet\" from \"endpoint missing\".\nAuthorization is the standard L4 API key (gated by `L4OpenapiApiKeyMiddleware`\non `/api/v1/edge/devices*`).","operationId":"list_enrolled_edge_devices_api_v1_edge_devices_enrolled_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/EnrolledEdgeDevice"},"type":"array","title":"Response List Enrolled Edge Devices Api V1 Edge Devices Enrolled Get"}}}}}}},"/api/v1/edge/devices":{"get":{"tags":["edge"],"summary":"List Edge Devices","operationId":"list_edge_devices_api_v1_edge_devices_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":2000,"minimum":1},{"type":"null"}],"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"sort","in":"query","required":false,"schema":{"anyOf":[{"enum":["device_id","vendor","profile_token_default","first_xaddr"],"type":"string"},{"type":"null"}],"title":"Sort"}},{"name":"order","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"asc","title":"Order"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"description":"Case-insensitive filter. Whitespace separates tokens; each token must appear as a substring in the merged searchable fields (device id, vendor, notes, profile, secret_ref, xaddrs, ONVIF profiles). Logical AND across tokens.","title":"Q"},"description":"Case-insensitive filter. Whitespace separates tokens; each token must appear as a substring in the merged searchable fields (device id, vendor, notes, profile, secret_ref, xaddrs, ONVIF profiles). Logical AND across tokens."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EdgeDeviceListResponse"}}}},"304":{"description":"Not Modified — `If-None-Match` matched current list representation"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/edge/devices/{device_id}":{"get":{"tags":["edge"],"summary":"Get Edge Device","operationId":"get_edge_device_api_v1_edge_devices__device_id__get","parameters":[{"name":"device_id","in":"path","required":true,"schema":{"type":"string","title":"Device Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EdgeDeviceItem"}}}},"304":{"description":"Not Modified — `If-None-Match` matched current device projection"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/edge/nodes":{"get":{"tags":["edge"],"summary":"List Edge Nodes","description":"List enrolled compute nodes (Jetsons) with their PKI lifecycle state.\n\n**BLK-059 backend (Wave-52).** Surfaces the per-Jetson registry — distinct\nfrom the camera-shaped `/api/v1/edge/devices` inventory (ADR-008\n`DeviceEntry`) — so an operator UI can see which compute nodes are enrolled\nat a site (CN, site_id, slug, enrollment status, cert serial, enrolled_at,\noptional last_seen_at, roles).\n\n**Read-only browser projection.** Candidate.35 registration mutations are\nserver-to-server, authenticated, transaction-journaled, and deliberately\nabsent from the L7 BFF allowlist.\n\n**L7 read-only surface.** This endpoint is on the **BFF allowlist** as\n`GET /api/proxy/edge/nodes` only; no detail path and no mutation surface are\nbrowser-reachable.\n\nReturns `200 { \"configured\": true, \"nodes\": [] }` when the registry file\nexists but is empty, and `200 { \"configured\": false, \"nodes\": [] }` when\nthe registry file does not exist (the documented \"not yet configured\" case\n— distinguishable from \"endpoint missing\" which would be 404).\n\nAuthorization is the standard L4 API key (gated by\n`L4OpenapiApiKeyMiddleware` on the `/api/v1/edge/` prefix).","operationId":"list_edge_nodes_api_v1_edge_nodes_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":2000,"minimum":1},{"type":"null"}],"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"site_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"description":"Exact match on `site_id` (parsed from the CN).","title":"Site Id"},"description":"Exact match on `site_id` (parsed from the CN)."},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"description":"Case-insensitive substring filter; whitespace-separated tokens must all appear in (cn, slug). Logical AND across tokens.","title":"Q"},"description":"Case-insensitive substring filter; whitespace-separated tokens must all appear in (cn, slug). Logical AND across tokens."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EdgeNodeListResponse"}}}},"304":{"description":"Not Modified — `If-None-Match` matched current node-list representation"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/edge/nodes/registrations":{"post":{"tags":["edge"],"summary":"Register Edge Node","operationId":"register_edge_node_api_v1_edge_nodes_registrations_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegistrationRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegistrationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/edge/nodes/registrations/{transaction_id}/rollback":{"post":{"tags":["edge"],"summary":"Rollback Edge Node Registration","operationId":"rollback_edge_node_registration_api_v1_edge_nodes_registrations__transaction_id__rollback_post","parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","title":"Transaction Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegistrationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/edge/nodes/registrations/{transaction_id}/commit":{"post":{"tags":["edge"],"summary":"Commit Edge Node Registration","operationId":"commit_edge_node_registration_api_v1_edge_nodes_registrations__transaction_id__commit_post","parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","title":"Transaction Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegistrationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/incidents/recent":{"get":{"tags":["incidents"],"summary":"Recent","description":"Return the engine's recent-incidents buffer (newest first).\n\n`SCENARIO_ENGINE_BASE_URL` must point at the engine's health server\n(e.g. `http://secureflow-scenario-engine.secureflow.svc.cluster.local:8080`).\nReturns 503 when the env var is unset — the feature isn't configured.\nReturns 502 if the engine is unreachable or returns malformed JSON.\n\n`scenario_id` / `site_id` / `device_id` are optional exact-match filters\ncombined with AND on the upstream side. FastAPI 422-s anything outside the\ncharset above (see `_IDENT_PATTERN`) — defence-in-depth so the proxy can't\nforward raw user input as a query string.","operationId":"recent_api_v1_incidents_recent_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":500,"minimum":0},{"type":"null"}],"title":"Limit"}},{"name":"scenario_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":128,"pattern":"^[a-zA-Z0-9_.:/-]+$"},{"type":"null"}],"title":"Scenario Id"}},{"name":"site_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":128,"pattern":"^[a-zA-Z0-9_.:/-]+$"},{"type":"null"}],"title":"Site Id"}},{"name":"device_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":128,"pattern":"^[a-zA-Z0-9_.:/-]+$"},{"type":"null"}],"title":"Device Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecentIncidentsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/incidents/{event_id}/state":{"get":{"tags":["incidents"],"summary":"Get Review State","description":"Return the current review state for ``event_id``.\n\nADR-014 Amendment M. 404 when no operator has approved/dismissed this event\nyet (the L7 UI already gets this signal inline on the ``/recent`` rows; this\nendpoint exists for direct lookup + full history view).","operationId":"get_review_state_api_v1_incidents__event_id__state_get","parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","maxLength":128,"pattern":"^[a-zA-Z0-9_.:/-]{1,128}$","title":"Event Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewStateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["incidents"],"summary":"Post Review State","description":"Record an approve/dismiss decision on ``event_id``.\n\nADR-014 Amendment M. Returns the new state object (current + history). The\nengine is the single source of truth — L4 validates shape and proxies; the\nengine validates + persists. Per-layer validation is intentional defence-in-depth.\n\nADR-014 Amendment P (2026-05-15) — when ``SECUREFLOW_REVIEWER_HEADER`` is\nset, the configured header's value overrides ``body.reviewer`` (and a\nmissing/empty header is 401). This lets an upstream auth-proxy bind the\nreviewer field to the authenticated identity instead of trusting the body.","operationId":"post_review_state_api_v1_incidents__event_id__state_post","parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","maxLength":128,"pattern":"^[a-zA-Z0-9_.:/-]{1,128}$","title":"Event Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewStateResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/vision/config":{"get":{"tags":["vision-config"],"summary":"Get Vision Config","description":"Return the YAML body verbatim + ETag, or 404 if none.","operationId":"get_vision_config_api_v1_vision_config_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"put":{"tags":["vision-config"],"summary":"Put Vision Config","description":"Replace the vision-config YAML; validate against the v1 schema.","operationId":"put_vision_config_api_v1_vision_config_put","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"delete":{"tags":["vision-config"],"summary":"Delete Vision Config","description":"Remove the vision-config file.","operationId":"delete_vision_config_api_v1_vision_config_delete","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/vision/config:validate":{"post":{"tags":["vision-config"],"summary":"Validate Vision Config","description":"Schema-validate the request body without persisting.","operationId":"validate_vision_config_api_v1_vision_config_validate_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/vision/drift-events":{"get":{"tags":["vision"],"summary":"Drift Events","description":"Return the engine's recent-drift-events buffer (newest first).\n\n``SCENARIO_ENGINE_BASE_URL`` must point at the engine's health server.\nReturns 503 when unset (feature not configured), 502 on upstream\nunreach/malformed JSON, 422 for bad query charsets.","operationId":"drift_events_api_v1_vision_drift_events_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":500,"minimum":0},{"type":"null"}],"title":"Limit"}},{"name":"model_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":128,"pattern":"^[a-zA-Z0-9_.:/-]+$"},{"type":"null"}],"title":"Model Name"}},{"name":"channel","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":32,"pattern":"^[a-zA-Z0-9_.:/-]+$"},{"type":"null"}],"title":"Channel"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriftEventsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/vision/face-events":{"get":{"tags":["vision"],"summary":"Face Events","description":"Return the engine's recent-face-events buffer (newest first).\n\n``SCENARIO_ENGINE_BASE_URL`` must point at the engine's health server.\nReturns 503 when unset (feature not configured), 502 on upstream\nunreach/malformed JSON, 422 for bad query charsets.","operationId":"face_events_api_v1_vision_face_events_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":500,"minimum":0},{"type":"null"}],"title":"Limit"}},{"name":"site_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":128,"pattern":"^[a-zA-Z0-9_.:/-]+$"},{"type":"null"}],"title":"Site Id"}},{"name":"device_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":128,"pattern":"^[a-zA-Z0-9_.:/-]+$"},{"type":"null"}],"title":"Device Id"}},{"name":"subject_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":128,"pattern":"^[a-zA-Z0-9_.:/-]+$"},{"type":"null"}],"title":"Subject Id"}},{"name":"event_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":32,"pattern":"^face\\.(known|unknown)$"},{"type":"null"}],"title":"Event Type"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FaceEventsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/slice1/metrics":{"get":{"tags":["slice1"],"summary":"Slice1 Metrics","description":"Aggregate slice-1 KPIs for the L7 dashboard. See module docstring.","operationId":"slice1_metrics_api_v1_slice1_metrics_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Slice1MetricsResponse"}}}}}}},"/api/v1/slo-burn-rate-summary":{"get":{"tags":["slo"],"summary":"Slo Burn Rate Summary","description":"Return SLO-1..SLO-13 burn-rate state for the operator dashboard.\n\nCached for ``_CACHE_TTL_S`` seconds so the 30 s L7 poll loop does not hammer\nPrometheus. When ``SECUREFLOW_PROMETHEUS_URL`` is unset, returns\n``configured=False`` with HTTP 200 so the UI renders an empty-state pane.","operationId":"slo_burn_rate_summary_api_v1_slo_burn_rate_summary_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SloBurnRateSummary"}}}}}}},"/api/v1/audit-log/streams":{"get":{"tags":["audit-log"],"summary":"List Streams","description":"List configured audit-log streams + on-disk metadata.\n\nReturns an empty ``streams: []`` only when ALL three configured streams\nhave an empty on-disk file (rare — the audit_log_appender + L4\nincident-log writers populate them on first event). Per-stream\n``present: false`` rows are included even when absent so the operator\ncan see which producer pods haven't booted yet.","operationId":"list_streams_api_v1_audit_log_streams_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/audit-log/streams/{name}/download":{"get":{"tags":["audit-log"],"summary":"Download Stream","description":"Stream a named audit log as text/plain JSONL.\n\nRange filtering uses the record's ``ts_ingested`` field. ``redact_pii=1``\nswaps every ``subject_id`` for a SHA-256 surrogate (defence-in-depth for\nthird-party auditors). On absent file → 404. The streaming response is\nchunked (8 KiB reads) and never buffers the full file.","operationId":"download_stream_api_v1_audit_log_streams__name__download_get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z][a-z0-9-]{0,31}$","title":"Name"}},{"name":"from","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"From"}},{"name":"to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"To"}},{"name":"redact_pii","in":"query","required":false,"schema":{"type":"integer","maximum":1,"minimum":0,"default":0,"title":"Redact Pii"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/audit-log/export":{"post":{"tags":["audit-log"],"summary":"Export Kickoff","description":"Kick off an async export of all three streams + return a job handle.\n\nCaller polls ``GET /api/v1/audit-log/export/{job_id}`` for status. The\ntarget file is gzipped at ``<exports_dir>/<job_id>.jsonl.gz`` and lives\n24 h before the operator's housekeeping should remove it.","operationId":"export_kickoff_api_v1_audit_log_export_post","parameters":[{"name":"from","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"From"}},{"name":"to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"To"}},{"name":"redact_pii","in":"query","required":false,"schema":{"type":"integer","maximum":1,"minimum":0,"default":0,"title":"Redact Pii"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/audit-log/export/{job_id}":{"get":{"tags":["audit-log"],"summary":"Export Status","description":"Return the current status of an export job (running / completed / failed).","operationId":"export_status_api_v1_audit_log_export__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","pattern":"^exp-[a-f0-9]{16}$","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/system-summary-export/json":{"get":{"tags":["system-summary-export"],"summary":"Export Bundle","description":"Stream the compliance bundle as JSON.\n\nDefault range is the last 24h. Use ``?since=…&until=…`` (ISO-8601 UTC) for\na different window. ``?limit=N`` clamps each inner list to N (max\n``MAX_LIST_LIMIT``). ``?redact_pii=1`` SHA-256 hashes every ``subject_id``\nfield — always set this for external auditors.","operationId":"export_bundle_api_v1_system_summary_export_json_get","parameters":[{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Since"}},{"name":"until","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Until"}},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":1000,"minimum":0},{"type":"null"}],"title":"Limit"}},{"name":"redact_pii","in":"query","required":false,"schema":{"type":"integer","maximum":1,"minimum":0,"default":0,"title":"Redact Pii"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/system-summary-export/manifest":{"get":{"tags":["system-summary-export"],"summary":"Export Manifest","description":"Cheap probe: returns item counts + the bundle sha256 without streaming\nthe full payload. The hash matches what ``/json`` will emit for the same\nparameters.","operationId":"export_manifest_api_v1_system_summary_export_manifest_get","parameters":[{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Since"}},{"name":"until","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Until"}},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":1000,"minimum":0},{"type":"null"}],"title":"Limit"}},{"name":"redact_pii","in":"query","required":false,"schema":{"type":"integer","maximum":1,"minimum":0,"default":0,"title":"Redact Pii"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/system-summary-export/sign":{"post":{"tags":["system-summary-export"],"summary":"Sign Bundle","description":"Cosign-sign the most recent bundle hash submitted in the request body\n(or a synthetic placeholder when none is supplied). Returns 503\nproblem+json when cosign isn't available.\n\nBody: ``{\"bundle_sha256\": \"<hex>\"}`` — when missing, the endpoint signs\na literal \"no-bundle\" sentinel so an operator can still test the signing\nseam.","operationId":"sign_bundle_api_v1_system_summary_export_sign_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/":{"get":{"summary":"Root","description":"Public root for Ingress health checks and human probes (avoids 404 on bare host).","operationId":"root__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"string"},"type":"object","title":"Response Root  Get"}}}}}}},"/health":{"get":{"summary":"Health","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"string"},"type":"object","title":"Response Health Health Get"}}}}}}},"/readyz":{"get":{"summary":"Readyz","description":"Readiness: optional MQTT handshake to L5 broker (see docs/api/l4-runtime-env.md).\n\nResult is cached for ``_READYZ_CACHE_TTL_S`` seconds so frequent UI polls\nand K8s readinessProbe calls do not each spawn a full paho CONNECT cycle.","operationId":"readyz_readyz_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"AgreementRate":{"properties":{"agreed":{"type":"integer","title":"Agreed","default":0},"total":{"type":"integer","title":"Total","default":0},"rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Rate","description":"agreed / total when total > 0; `null` when there are no reviewed incidents in the 7-day window (the L7 KPI card shows '—' then)."}},"type":"object","title":"AgreementRate"},"AuthorityShadowMetrics":{"properties":{"total":{"type":"integer","title":"Total","default":0},"by_result":{"additionalProperties":{"type":"integer"},"type":"object","title":"By Result"},"by_site":{"additionalProperties":{"type":"integer"},"type":"object","title":"By Site"},"by_site_result":{"additionalProperties":{"additionalProperties":{"type":"integer"},"type":"object"},"type":"object","title":"By Site Result"}},"type":"object","title":"AuthorityShadowMetrics"},"DriftEventEntry":{"properties":{"recorded_at":{"type":"string","title":"Recorded At"},"event_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Id"},"model_name":{"type":"string","title":"Model Name"},"channel":{"type":"string","title":"Channel"},"expected_digest":{"type":"string","title":"Expected Digest"},"observed_digest":{"type":"string","title":"Observed Digest"},"occurred_at":{"type":"string","title":"Occurred At"},"site_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Site Id"},"camera_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Camera Id"},"host_machine":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Host Machine"},"inference_backend":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Inference Backend"}},"type":"object","required":["recorded_at","event_id","model_name","channel","expected_digest","observed_digest","occurred_at"],"title":"DriftEventEntry"},"DriftEventsResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/DriftEventEntry"},"type":"array","title":"Items"},"count":{"type":"integer","title":"Count","description":"Length of `items` after any limit/clamp"}},"type":"object","required":["items","count"],"title":"DriftEventsResponse"},"EdgeDeviceItem":{"properties":{"device_id":{"type":"string","minLength":1,"title":"Device Id"},"vendor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vendor"},"profile_token_default":{"type":"string","minLength":1,"title":"Profile Token Default"},"xaddrs":{"items":{"type":"string"},"type":"array","minItems":1,"title":"Xaddrs"},"onvif_profiles_supported":{"items":{"type":"string"},"type":"array","title":"Onvif Profiles Supported"},"secret_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Secret Ref"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","required":["device_id","profile_token_default","xaddrs"],"title":"EdgeDeviceItem","description":"Public projection of a row from device inventory v1 (no secrets)."},"EdgeDeviceListResponse":{"properties":{"inventory_schema_version":{"type":"integer","title":"Inventory Schema Version","default":1},"configured":{"type":"boolean","title":"Configured"},"inventory_dir":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Inventory Dir"},"devices":{"items":{"$ref":"#/components/schemas/EdgeDeviceItem"},"type":"array","title":"Devices"},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total"},"limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Limit"},"offset":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Offset"}},"type":"object","required":["configured","devices"],"title":"EdgeDeviceListResponse"},"EdgeNode":{"properties":{"cn":{"type":"string","minLength":1,"title":"Cn","description":"Client-cert Common Name in the `<slug>@<site-id>` form (ADR-022)."},"site_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Site Id","description":"Site slug parsed from the CN. `None` when the CN is malformed."},"slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Slug","description":"Per-Jetson hostname slug parsed from the CN. `None` when the CN is malformed."},"enrollment_status":{"type":"string","enum":["pending","active","revoked"],"title":"Enrollment Status","description":"Lifecycle state of the enrollment record: `pending` (CSR submitted, cert not yet issued), `active` (cert issued + not revoked), `revoked` (cert revoked via OpenBao PKI). Unknown / missing values default to `active`.","default":"active"},"enrolled_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Enrolled At","description":"ISO-8601 UTC timestamp of the OpenBao PKI issue event. `None` for pre-Wave-52 records."},"last_seen_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Seen At","description":"ISO-8601 UTC timestamp of the most recent heartbeat / MQTT publish from this CN, when a heartbeat source is wired. `None` when no heartbeat has been recorded (or the source is not yet plumbed)."},"cert_serial":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cert Serial","description":"OpenBao PKI certificate serial (hex). `None` for pre-Wave-52 records."},"roles":{"items":{"type":"string"},"type":"array","title":"Roles","description":"Logical roles active on this node (e.g. `[\"edge-agent\", \"vision\"]`). ADR-005 Amendment C host-docker edge nodes share one CN across both roles."},"camera_ip":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Camera Ip"},"candidate_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Candidate Id"},"candidate_digest":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Candidate Digest"}},"type":"object","required":["cn"],"title":"EdgeNode","description":"Per-Jetson enrollment-lifecycle row (ADR-022 + BLK-059).\n\nRead-only projection row. Mutations occur only through the authenticated\ncentral onboarding transaction. The CN is the primary key (matches the mosquitto ACL\nkey per CLAUDE.md §\"How you hand off\"). `site_id` + `slug` are parsed at\nread time so the on-disk shape stays minimal and a malformed CN row is\nstill surfaced (operator can see misconfiguration rather than silent drop)."},"EdgeNodeListResponse":{"properties":{"registry_schema_version":{"type":"integer","title":"Registry Schema Version","default":1},"configured":{"type":"boolean","title":"Configured"},"registry_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Registry Path"},"nodes":{"items":{"$ref":"#/components/schemas/EdgeNode"},"type":"array","title":"Nodes"},"total":{"type":"integer","title":"Total","default":0},"limit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Limit"},"offset":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Offset"}},"type":"object","required":["configured","nodes"],"title":"EdgeNodeListResponse","description":"Paginated list response. `configured: false` when the registry env is unset."},"EnrolledEdgeDevice":{"properties":{"cn":{"type":"string","minLength":1,"title":"Cn","description":"Client-cert Common Name in the `<slug>@<site-id>` form (ADR-022)."},"site_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Site Id","description":"Site slug parsed from the CN. `None` when the CN is malformed."},"slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Slug","description":"Per-Jetson hostname slug parsed from the CN. `None` when the CN is malformed."},"last_seen":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Seen","description":"ISO-8601 UTC timestamp of the most recent MQTT publish from this CN (read via the L5 event index). `None` when the node has not yet connected."},"model_channel_pins":{"items":{"type":"string"},"type":"array","title":"Model Channel Pins","description":"Vision-config channel pins active on this Jetson (e.g. `[\"plate@v3\", \"face@v2\"]`)."},"last_action_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Action At","description":"ISO-8601 UTC timestamp of the most recent actuation command dispatched to this CN (or `None` if none yet)."},"last_shadow_decision_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Shadow Decision At","description":"ISO-8601 UTC timestamp of the most recent shadow-mode decision (ADR-018 §2.3) for this CN, or `None`."},"last_incident_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Incident Id","description":"Most recent incident UUID for this site, or `None` when no incidents have been recorded."}},"type":"object","required":["cn"],"title":"EnrolledEdgeDevice","description":"Per-Jetson enrolled-state row (ADR-022 + Wave-44 BLK-031).\n\nRead-only projection; mutations occur via the ADR-022 enrollment handshake\non the Jetson side, never via this L4 surface. The CN is the primary key\n(matches the mosquitto ACL key per CLAUDE.md §\"How you hand off\")."},"FaceEventEntry":{"properties":{"recorded_at":{"type":"string","title":"Recorded At"},"event_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Id"},"event_type":{"type":"string","title":"Event Type"},"occurred_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Occurred At"},"site_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Site Id"},"camera_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Camera Id"},"subject_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subject Id"},"peer_digest":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Peer Digest"},"embedding_dim":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Embedding Dim"},"similarity_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Similarity Score"},"identity_match_threshold":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Identity Match Threshold"},"confidence":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Confidence"},"zone_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Zone Id"},"lane":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lane"}},"type":"object","required":["recorded_at","event_id","event_type"],"title":"FaceEventEntry"},"FaceEventsResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/FaceEventEntry"},"type":"array","title":"Items"},"count":{"type":"integer","title":"Count","description":"Length of `items` after any limit/clamp"}},"type":"object","required":["items","count"],"title":"FaceEventsResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"IncidentEntry":{"properties":{"recorded_at":{"type":"string","title":"Recorded At"},"event_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Id"},"event_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Type"},"event_time":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Time"},"scenario_id":{"type":"string","title":"Scenario Id"},"scenario":{"anyOf":[{"$ref":"#/components/schemas/IncidentScenarioMeta"},{"type":"null"}]},"actions":{"items":{"type":"string"},"type":"array","title":"Actions"},"site_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Site Id"},"device_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Device Id"},"identity":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Identity"},"payload_summary":{"additionalProperties":true,"type":"object","title":"Payload Summary"},"review":{"anyOf":[{"$ref":"#/components/schemas/IncidentReview"},{"type":"null"}]},"media":{"anyOf":[{"$ref":"#/components/schemas/IncidentMedia"},{"type":"null"}]}},"type":"object","required":["recorded_at","event_id","event_type","event_time","scenario_id","actions","site_id","device_id"],"title":"IncidentEntry"},"IncidentMedia":{"properties":{"crop_signed_url":{"type":"string","title":"Crop Signed Url"},"crop_signed_url_ttl_s":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Crop Signed Url Ttl S"},"crop_mime":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Crop Mime"}},"type":"object","required":["crop_signed_url"],"title":"IncidentMedia","description":"ADR-014 Amendment M follow-on — operator-facing crop thumbnail.\n\nOnly ``crop_signed_url`` leaves L4. The raw object-store pointer (bucket /\nkey / path) lives inside L4 as input to the signer and is stripped from\nevery response so a logged-out browser can't enumerate the bucket.\n\n``crop_signed_url_ttl_s`` reflects the TTL L4 requested from the signer\n(capped at 300 s). When the engine prefilled the URL with its own signer\nthe field is opaque to L4 and the TTL is omitted — the L7 UI's expiry\nfallback (refetch on click) still works because the click round-trips\nthrough L4 which always re-mints fresh."},"IncidentReview":{"properties":{"action":{"type":"string","title":"Action"},"reviewer":{"type":"string","title":"Reviewer"},"reviewed_at":{"type":"string","title":"Reviewed At"},"note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Note"}},"type":"object","required":["action","reviewer","reviewed_at"],"title":"IncidentReview","description":"ADR-014 Amendment M — current operator review state on a buffered incident."},"IncidentScenarioMeta":{"properties":{"capability":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Capability"},"autonomy_rung":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Autonomy Rung"}},"type":"object","title":"IncidentScenarioMeta","description":"Wave-60 Track C — sibling scenario metadata resolved by L4 from the\nloaded scenario catalogue (the same ``SECUREFLOW_SCENARIO_DIR`` that\nbacks ``/api/v1/scenarios``).\n\n- ``capability`` — ADR-042 six-verb capability label (Sense / Reason /\n  Decide / Act / Govern / Secure). The scenario-engine treats the field\n  as required; L4 surfaces it best-effort (``None`` if absent in YAML\n  because the catalogue lookup pre-dates the strict validation).\n- ``autonomy_rung`` — ADR-018 Amendment B autonomy rung. Defaults to\n  ``\"R1\"`` per Amendment B §\"default rung\" when the YAML omits the\n  field. R2/R3 only appear when the operator has explicitly opted in\n  via ``SECUREFLOW_H1_ONLY=0`` (the H2 ceiling toggle).\n\nBoth fields are OPTIONAL on the L4 wire so the response stays back-\ncompat: a scenario that is no longer present in the catalogue (e.g.\ndeleted between buffer-record and read), or a scenario YAML that\npre-dates the labelled-rung surface, yields ``scenario: null`` (the\nblock is omitted from the JSON entirely). The L7 chip defensively\nfalls back to R1 in that case (see ``frontend/src/components/\nautonomy-chip.tsx`` + ``resolveAutonomyRung``)."},"MetricsSnapshot":{"properties":{"enabled":{"type":"boolean","title":"Enabled"},"http_requests_total":{"type":"number","title":"Http Requests Total","default":0},"http_avg_latency_ms":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Http Avg Latency Ms"},"edge_devices_list_observations":{"type":"integer","title":"Edge Devices List Observations","default":0},"edge_devices_list_avg_ms":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Edge Devices List Avg Ms"},"edge_devices_detail_observations":{"type":"integer","title":"Edge Devices Detail Observations","default":0},"edge_devices_detail_avg_ms":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Edge Devices Detail Avg Ms"},"edge_q_index_watch_ok_cycles":{"type":"integer","title":"Edge Q Index Watch Ok Cycles","default":0},"edge_q_index_watch_error_cycles":{"type":"integer","title":"Edge Q Index Watch Error Cycles","default":0},"edge_q_index_watch_last_ok_unix_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Edge Q Index Watch Last Ok Unix Seconds"},"edge_q_index_watch_last_error_unix_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Edge Q Index Watch Last Error Unix Seconds"},"edge_q_index_watch_avg_cycle_ms":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Edge Q Index Watch Avg Cycle Ms"}},"type":"object","required":["enabled"],"title":"MetricsSnapshot"},"MqttStatus":{"properties":{"reachable":{"type":"boolean","title":"Reachable"},"broker":{"type":"string","title":"Broker"},"port":{"type":"integer","title":"Port"},"skipped":{"type":"boolean","title":"Skipped","default":false}},"type":"object","required":["reachable","broker","port"],"title":"MqttStatus"},"RecentIncidentsResponse":{"properties":{"items":{"items":{"$ref":"#/components/schemas/IncidentEntry"},"type":"array","title":"Items"},"count":{"type":"integer","title":"Count","description":"Length of `items` after any limit/clamp"}},"type":"object","required":["items","count"],"title":"RecentIncidentsResponse"},"RegistrationNode":{"properties":{"cn":{"type":"string","maxLength":300,"minLength":3,"title":"Cn"},"site_id":{"type":"string","maxLength":200,"minLength":1,"title":"Site Id"},"slug":{"type":"string","maxLength":200,"minLength":1,"title":"Slug"},"camera_ip":{"type":"string","maxLength":64,"minLength":1,"title":"Camera Ip"},"candidate_id":{"type":"string","maxLength":63,"minLength":2,"title":"Candidate Id"},"candidate_digest":{"type":"string","maxLength":71,"minLength":71,"title":"Candidate Digest"},"enrollment_status":{"type":"string","const":"active","title":"Enrollment Status","default":"active"},"roles":{"items":{"type":"string"},"type":"array","title":"Roles"}},"type":"object","required":["cn","site_id","slug","camera_ip","candidate_id","candidate_digest"],"title":"RegistrationNode"},"RegistrationRequest":{"properties":{"transaction_id":{"type":"string","maxLength":63,"minLength":2,"title":"Transaction Id"},"node":{"$ref":"#/components/schemas/RegistrationNode"}},"type":"object","required":["transaction_id","node"],"title":"RegistrationRequest"},"RegistrationResponse":{"properties":{"transaction_id":{"type":"string","title":"Transaction Id"},"status":{"type":"string","enum":["applied","idempotent","committed","rolled_back"],"title":"Status"},"node":{"anyOf":[{"$ref":"#/components/schemas/RegistrationNode"},{"type":"null"}]},"registry_revision":{"type":"string","title":"Registry Revision"}},"type":"object","required":["transaction_id","status","registry_revision"],"title":"RegistrationResponse"},"ReviewRequest":{"properties":{"action":{"type":"string","title":"Action","description":"One of: approve | dismiss"},"reviewer":{"type":"string","maxLength":128,"minLength":1,"title":"Reviewer"},"note":{"anyOf":[{"type":"string","maxLength":512},{"type":"null"}],"title":"Note"}},"type":"object","required":["action","reviewer"],"title":"ReviewRequest","description":"Body for `POST /api/v1/incidents/{event_id}/state`."},"ReviewStateResponse":{"properties":{"current":{"$ref":"#/components/schemas/IncidentReview"},"history":{"items":{"$ref":"#/components/schemas/IncidentReview"},"type":"array","title":"History"}},"type":"object","required":["current"],"title":"ReviewStateResponse","description":"Engine-returned state object — current + capped history."},"ScenarioDetailResponse":{"properties":{"scenario_id":{"type":"string","title":"Scenario Id"},"source_file":{"type":"string","title":"Source File"},"document":{"additionalProperties":true,"type":"object","title":"Document"},"validation":{"$ref":"#/components/schemas/ScenarioValidation"}},"type":"object","required":["scenario_id","source_file","document","validation"],"title":"ScenarioDetailResponse"},"ScenarioListItem":{"properties":{"scenario_id":{"type":"string","title":"Scenario Id"},"source_file":{"type":"string","title":"Source File"},"validation":{"$ref":"#/components/schemas/ScenarioValidation"}},"type":"object","required":["scenario_id","source_file","validation"],"title":"ScenarioListItem"},"ScenarioListResponse":{"properties":{"scenarios":{"items":{"$ref":"#/components/schemas/ScenarioListItem"},"type":"array","title":"Scenarios"},"scenario_dir":{"type":"string","title":"Scenario Dir"}},"type":"object","required":["scenario_dir"],"title":"ScenarioListResponse"},"ScenarioOverview":{"properties":{"total":{"type":"integer","title":"Total","default":0},"valid":{"type":"integer","title":"Valid","default":0},"invalid":{"type":"integer","title":"Invalid","default":0},"directory":{"type":"string","title":"Directory","default":""}},"type":"object","title":"ScenarioOverview"},"ScenarioValidation":{"properties":{"ok":{"type":"boolean","title":"Ok"},"issues":{"items":{"type":"string"},"type":"array","title":"Issues"}},"type":"object","required":["ok"],"title":"ScenarioValidation"},"ScenarioWriteBody":{"properties":{"document":{"additionalProperties":true,"type":"object","title":"Document"}},"type":"object","required":["document"],"title":"ScenarioWriteBody","description":"JSON body matching on-disk YAML shape (scenario, trigger, actions, …)."},"Slice1MetricsResponse":{"properties":{"generated_at":{"type":"string","title":"Generated At"},"window":{"$ref":"#/components/schemas/Window"},"plate_reads_last_hour":{"type":"integer","title":"Plate Reads Last Hour","default":0},"barrier_actions_last_hour":{"type":"integer","title":"Barrier Actions Last Hour","default":0},"agreement_rate_7d":{"$ref":"#/components/schemas/AgreementRate"},"model_loaded_last_24h":{"type":"integer","title":"Model Loaded Last 24H","default":0},"authority_shadow":{"$ref":"#/components/schemas/AuthorityShadowMetrics"},"recent_plate_reads":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Recent Plate Reads"}},"type":"object","required":["generated_at"],"title":"Slice1MetricsResponse"},"SloBurnRateSummary":{"properties":{"configured":{"type":"boolean","title":"Configured","description":"True when SECUREFLOW_PROMETHEUS_URL is set and reachable."},"slos":{"items":{"$ref":"#/components/schemas/SloRow"},"type":"array","title":"Slos"}},"type":"object","required":["configured"],"title":"SloBurnRateSummary","description":"Top-level shape the L7 tile consumes."},"SloRow":{"properties":{"name":{"type":"string","title":"Name","description":"Catalogue identifier — e.g. 'SLO-1'."},"description":{"type":"string","title":"Description","description":"Human-readable SLO description."},"burn_rate_state":{"type":"string","title":"Burn Rate State","description":"One of 'ok', 'slow', 'fast', 'saturated'."},"alerts_firing":{"type":"integer","title":"Alerts Firing","description":"Count of firing burn-rate alerts for this SLO."},"last_eval_ts":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Eval Ts","description":"ISO-8601 timestamp of the most recent Prometheus eval."}},"type":"object","required":["name","description","burn_rate_state","alerts_firing"],"title":"SloRow","description":"One operator-dashboard row for a single SLO."},"SummaryEntry":{"properties":{"count":{"type":"integer","title":"Count"},"newest_ts":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Newest Ts"}},"type":"object","required":["count"],"title":"SummaryEntry","description":"Per-buffer entry on the aggregate response.\n\n``count`` is the total number of items currently in the engine's ring\nbuffer (capped at the engine's hard limit; ``-1`` when unknown / not\nreturned). ``newest_ts`` is the validated ISO-8601 timestamp of the most\nrecent item, or ``null`` when the buffer is empty or the engine\nmisbehaved."},"SystemEventSummaryResponse":{"properties":{"incidents":{"anyOf":[{"$ref":"#/components/schemas/SummaryEntry"},{"type":"null"}]},"barrier_results":{"anyOf":[{"$ref":"#/components/schemas/SummaryEntry"},{"type":"null"}]},"drift_events":{"anyOf":[{"$ref":"#/components/schemas/SummaryEntry"},{"type":"null"}]},"barrier_acks":{"anyOf":[{"$ref":"#/components/schemas/SummaryEntry"},{"type":"null"}]},"summary_at":{"type":"string","title":"Summary At"}},"type":"object","required":["summary_at"],"title":"SystemEventSummaryResponse","description":"Top-level shape returned by ``GET /api/v1/system-event-summary``."},"SystemStatusResponse":{"properties":{"service":{"type":"string","title":"Service","default":"secureflow-api"},"version":{"type":"string","title":"Version"},"uptime_seconds":{"type":"number","title":"Uptime Seconds"},"timestamp":{"type":"number","title":"Timestamp"},"mqtt":{"$ref":"#/components/schemas/MqttStatus"},"scenarios":{"$ref":"#/components/schemas/ScenarioOverview"},"metrics":{"$ref":"#/components/schemas/MetricsSnapshot"},"environment":{"additionalProperties":{"type":"string"},"type":"object","title":"Environment"},"autonomy_rung":{"type":"string","enum":["R1","R2","R3"],"title":"Autonomy Rung","default":"R1"}},"type":"object","required":["version","uptime_seconds","timestamp","mqtt","scenarios","metrics"],"title":"SystemStatusResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"Window":{"properties":{"plate_reads_seconds":{"type":"integer","title":"Plate Reads Seconds","default":3600},"barrier_actions_seconds":{"type":"integer","title":"Barrier Actions Seconds","default":3600},"agreement_rate_days":{"type":"integer","title":"Agreement Rate Days","default":7},"model_loaded_seconds":{"type":"integer","title":"Model Loaded Seconds","default":86400}},"type":"object","title":"Window"}}}}