{
  "schema_version": 1,
  "schemaVersion": "0.1.0",
  "adminApiVersion": 1,
  "client_required": false,
  "host_script_runtime_required": false,
  "authority": "Discovery metadata only. Installed capabilities, verified identity and daemon governance decide availability.",
  "discovery": {
    "identity": "getAdminIdentity",
    "inspection": "getAdminDashboard",
    "openapi": "openapi.json",
    "workflows": "workflow-catalog.json"
  },
  "stages": [
    "discover",
    "inspect",
    "validate",
    "execute",
    "verify"
  ],
  "result_contract": {
    "success_state": "reconciled",
    "pending_state": "accepted_pending",
    "failure_states": [
      "blocked",
      "rejected",
      "failed"
    ],
    "http_acceptance_is_completion": false,
    "status_get_changes_state": false,
    "unknown_post_outcome": "Keep the exact intent and idempotency key. Recover a unique exact intent match through bounded GETs of daemon events and command status; never resubmit a new key to obtain status."
  },
  "tasks": [
    {
      "id": "getAdminIdentity",
      "method": "GET",
      "path": "/api/v1/admin/identity",
      "summary": "Stable API identity, role vocabulary, and current trusted-edge role",
      "required_role": "viewer",
      "inputs": [],
      "side_effects": "None; read-only observation.",
      "completion": "A version-compatible response; assess its freshness and readiness independently."
    },
    {
      "id": "getLive",
      "method": "GET",
      "path": "/live",
      "summary": "Process liveness",
      "required_role": "viewer",
      "inputs": [],
      "side_effects": "None; read-only observation.",
      "completion": "A version-compatible response; assess its freshness and readiness independently."
    },
    {
      "id": "getReady",
      "method": "GET",
      "path": "/ready",
      "summary": "Route readiness",
      "required_role": "viewer",
      "inputs": [],
      "side_effects": "None; read-only observation.",
      "completion": "A version-compatible response; assess its freshness and readiness independently."
    },
    {
      "id": "getHealthDetails",
      "method": "GET",
      "path": "/health/details",
      "summary": "Detailed health / HA facts",
      "required_role": "viewer",
      "inputs": [],
      "side_effects": "None; read-only observation.",
      "completion": "A version-compatible response; assess its freshness and readiness independently."
    },
    {
      "id": "getAdminDashboard",
      "method": "GET",
      "path": "/api/v1/admin/dashboard",
      "summary": "Panel-contract dashboard snapshot",
      "required_role": "viewer",
      "inputs": [],
      "side_effects": "None; read-only observation.",
      "completion": "A version-compatible response; assess its freshness and readiness independently."
    },
    {
      "id": "getAdminClients",
      "method": "GET",
      "path": "/api/v1/admin/clients",
      "summary": "Paginated connected clients",
      "required_role": "viewer",
      "inputs": [
        {
          "name": "offset",
          "in": "query",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 0,
            "default": 0
          }
        },
        {
          "name": "limit",
          "in": "query",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 1,
            "maximum": 200,
            "default": 50
          }
        },
        {
          "name": "q",
          "in": "query",
          "required": false,
          "schema": {
            "type": "string",
            "maxLength": 64
          }
        }
      ],
      "side_effects": "None; read-only observation.",
      "completion": "A version-compatible response; assess its freshness and readiness independently."
    },
    {
      "id": "getAdminSessions",
      "method": "GET",
      "path": "/api/v1/admin/sessions",
      "summary": "Paginated sessions",
      "required_role": "viewer",
      "inputs": [
        {
          "name": "offset",
          "in": "query",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 0,
            "default": 0
          }
        },
        {
          "name": "limit",
          "in": "query",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 1,
            "maximum": 200,
            "default": 50
          }
        },
        {
          "name": "q",
          "in": "query",
          "required": false,
          "schema": {
            "type": "string",
            "maxLength": 64
          }
        },
        {
          "name": "state",
          "in": "query",
          "required": false,
          "schema": {
            "type": "string",
            "enum": [
              "connected",
              "disconnected"
            ]
          }
        }
      ],
      "side_effects": "None; read-only observation.",
      "completion": "A version-compatible response; assess its freshness and readiness independently."
    },
    {
      "id": "getAdminSubscriptions",
      "method": "GET",
      "path": "/api/v1/admin/subscriptions",
      "summary": "Paginated subscriptions",
      "required_role": "viewer",
      "inputs": [
        {
          "name": "offset",
          "in": "query",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 0,
            "default": 0
          }
        },
        {
          "name": "limit",
          "in": "query",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 1,
            "maximum": 200,
            "default": 50
          }
        },
        {
          "name": "q",
          "in": "query",
          "required": false,
          "schema": {
            "type": "string",
            "maxLength": 64
          }
        }
      ],
      "side_effects": "None; read-only observation.",
      "completion": "A version-compatible response; assess its freshness and readiness independently."
    },
    {
      "id": "getAdminRetained",
      "method": "GET",
      "path": "/api/v1/admin/retained",
      "summary": "Paginated retained message summaries (payload-free)",
      "required_role": "viewer",
      "inputs": [
        {
          "name": "offset",
          "in": "query",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 0,
            "default": 0
          }
        },
        {
          "name": "limit",
          "in": "query",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 1,
            "maximum": 200,
            "default": 50
          }
        },
        {
          "name": "q",
          "in": "query",
          "required": false,
          "schema": {
            "type": "string",
            "maxLength": 64
          }
        }
      ],
      "side_effects": "None; read-only observation.",
      "completion": "A version-compatible response; assess its freshness and readiness independently."
    },
    {
      "id": "getAdminOfflineQueues",
      "method": "GET",
      "path": "/api/v1/admin/offline-queues",
      "summary": "Paginated offline queue summaries (payload-free)",
      "required_role": "viewer",
      "inputs": [
        {
          "name": "offset",
          "in": "query",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 0,
            "default": 0
          }
        },
        {
          "name": "limit",
          "in": "query",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 1,
            "maximum": 200,
            "default": 50
          }
        },
        {
          "name": "q",
          "in": "query",
          "required": false,
          "schema": {
            "type": "string",
            "maxLength": 64
          }
        }
      ],
      "side_effects": "None; read-only observation.",
      "completion": "A version-compatible response; assess its freshness and readiness independently."
    },
    {
      "id": "getAdminBridges",
      "method": "GET",
      "path": "/api/v1/admin/bridges",
      "summary": "Shared guardian summary and paginated isolated bridge worker status rows",
      "required_role": "viewer",
      "inputs": [
        {
          "name": "offset",
          "in": "query",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 0,
            "default": 0
          }
        },
        {
          "name": "limit",
          "in": "query",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 1,
            "maximum": 200,
            "default": 50
          }
        },
        {
          "name": "q",
          "in": "query",
          "required": false,
          "schema": {
            "type": "string",
            "maxLength": 64
          }
        },
        {
          "name": "state",
          "in": "query",
          "required": false,
          "schema": {
            "type": "string",
            "enum": [
              "healthy",
              "degraded",
              "standby",
              "failed",
              "draining"
            ]
          }
        }
      ],
      "side_effects": "None; read-only observation.",
      "completion": "A version-compatible response; assess its freshness and readiness independently."
    },
    {
      "id": "getAdminRules",
      "method": "GET",
      "path": "/api/v1/admin/rules",
      "summary": "Paginated rules",
      "required_role": "viewer",
      "inputs": [
        {
          "name": "offset",
          "in": "query",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 0,
            "default": 0
          }
        },
        {
          "name": "limit",
          "in": "query",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 1,
            "maximum": 200,
            "default": 50
          }
        },
        {
          "name": "q",
          "in": "query",
          "required": false,
          "schema": {
            "type": "string",
            "maxLength": 64
          }
        },
        {
          "name": "state",
          "in": "query",
          "required": false,
          "schema": {
            "type": "string",
            "enum": [
              "enabled",
              "disabled"
            ]
          }
        }
      ],
      "side_effects": "None; read-only observation.",
      "completion": "A version-compatible response; assess its freshness and readiness independently."
    },
    {
      "id": "getAdminSchemas",
      "method": "GET",
      "path": "/api/v1/admin/schemas",
      "summary": "Paginated schema registry summaries",
      "required_role": "viewer",
      "inputs": [
        {
          "name": "offset",
          "in": "query",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 0,
            "default": 0
          }
        },
        {
          "name": "limit",
          "in": "query",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 1,
            "maximum": 200,
            "default": 50
          }
        },
        {
          "name": "q",
          "in": "query",
          "required": false,
          "schema": {
            "type": "string",
            "maxLength": 64
          }
        },
        {
          "name": "state",
          "in": "query",
          "required": false,
          "schema": {
            "type": "string",
            "enum": [
              "active",
              "inactive"
            ]
          }
        }
      ],
      "side_effects": "None; read-only observation.",
      "completion": "A version-compatible response; assess its freshness and readiness independently."
    },
    {
      "id": "getAdminGateways",
      "method": "GET",
      "path": "/api/v1/admin/gateways",
      "summary": "Paginated gateway status",
      "required_role": "viewer",
      "inputs": [
        {
          "name": "offset",
          "in": "query",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 0,
            "default": 0
          }
        },
        {
          "name": "limit",
          "in": "query",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 1,
            "maximum": 200,
            "default": 50
          }
        },
        {
          "name": "q",
          "in": "query",
          "required": false,
          "schema": {
            "type": "string",
            "maxLength": 64
          }
        },
        {
          "name": "state",
          "in": "query",
          "required": false,
          "schema": {
            "type": "string",
            "enum": [
              "installed-runtime-certified"
            ]
          }
        }
      ],
      "side_effects": "None; read-only observation.",
      "completion": "A version-compatible response; assess its freshness and readiness independently."
    },
    {
      "id": "getAdminAudit",
      "method": "GET",
      "path": "/api/v1/admin/audit",
      "summary": "Paginated audit records (redacted)",
      "required_role": "viewer",
      "inputs": [
        {
          "name": "offset",
          "in": "query",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 0,
            "default": 0
          }
        },
        {
          "name": "limit",
          "in": "query",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 1,
            "maximum": 200,
            "default": 50
          }
        },
        {
          "name": "q",
          "in": "query",
          "required": false,
          "schema": {
            "type": "string",
            "maxLength": 64
          }
        },
        {
          "name": "state",
          "in": "query",
          "required": false,
          "schema": {
            "type": "string",
            "enum": [
              "allow",
              "deny"
            ]
          }
        }
      ],
      "side_effects": "None; read-only observation.",
      "completion": "A version-compatible response; assess its freshness and readiness independently."
    },
    {
      "id": "getAdminSupport",
      "method": "GET",
      "path": "/api/v1/admin/support",
      "summary": "Support bundle metadata (safe-to-share flags)",
      "required_role": "viewer",
      "inputs": [],
      "side_effects": "None; read-only observation.",
      "completion": "A version-compatible response; assess its freshness and readiness independently."
    },
    {
      "id": "getAdminHa",
      "method": "GET",
      "path": "/api/v1/admin/ha",
      "summary": "HA readiness projection",
      "required_role": "viewer",
      "inputs": [],
      "side_effects": "None; read-only observation.",
      "completion": "A version-compatible response; assess its freshness and readiness independently."
    },
    {
      "id": "getAdminMetrics",
      "method": "GET",
      "path": "/api/v1/admin/metrics",
      "summary": "Bounded metrics summary",
      "required_role": "viewer",
      "inputs": [],
      "side_effects": "None; read-only observation.",
      "completion": "A version-compatible response; assess its freshness and readiness independently."
    },
    {
      "id": "getAdminMetricHistory",
      "method": "GET",
      "path": "/api/v1/admin/metrics/history",
      "summary": "Backend-owned 30-second metric history at a fixed one-second cadence",
      "required_role": "viewer",
      "inputs": [],
      "side_effects": "None; read-only observation.",
      "completion": "A version-compatible response; assess its freshness and readiness independently."
    },
    {
      "id": "postControlledDrain",
      "method": "POST",
      "path": "/api/v1/admin/drain",
      "summary": "Request controlled node drain (HTTP fail-closed until RBAC/SSO; never completes on 2xx)",
      "required_role": "operator_admin",
      "inputs": [
        {
          "name": "idempotency_key",
          "in": "query",
          "required": true,
          "schema": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          }
        },
        {
          "name": "expected_generation",
          "in": "query",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[0-9]+$"
          }
        },
        {
          "name": "expected_writer_term",
          "in": "query",
          "required": true,
          "schema": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20,
            "pattern": "^[0-9]+$"
          }
        },
        {
          "name": "target",
          "in": "query",
          "required": true,
          "schema": {
            "type": "string",
            "minLength": 1,
            "maxLength": 96,
            "pattern": "^[A-Za-z0-9._:@/-]+$"
          }
        }
      ],
      "side_effects": "Withdraw this node from routing; does not fence or promote another node.",
      "completion": "Only a reconciled record with matching intent, commandId, auditId and reconciliation.evidence proves completion.",
      "workflow_id": "controlled_drain",
      "compatible_roles": [],
      "idempotency": "Caller supplies a stable idempotency_key for one intent. Reuse only with identical inputs. Never automatically retry an ambiguous POST.",
      "verify_operation": "getAdminCommand"
    },
    {
      "id": "postBridgeDrain",
      "method": "POST",
      "path": "/api/v1/admin/bridges/{id}/drain",
      "summary": "Request bridge drain (HTTP fail-closed until RBAC/SSO; never completes on 2xx)",
      "required_role": "operator_admin",
      "inputs": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "idempotency_key",
          "in": "query",
          "required": true,
          "schema": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          }
        },
        {
          "name": "expected_generation",
          "in": "query",
          "required": true,
          "schema": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20,
            "pattern": "^[0-9]+$"
          }
        },
        {
          "name": "expected_writer_term",
          "in": "query",
          "required": true,
          "schema": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20,
            "pattern": "^[0-9]+$"
          }
        },
        {
          "name": "target",
          "in": "query",
          "required": true,
          "schema": {
            "type": "string",
            "minLength": 1,
            "maxLength": 96,
            "pattern": "^[A-Za-z0-9._:@/-]+$"
          }
        }
      ],
      "side_effects": "Drain the explicitly selected bridge; external sink effects may already exist.",
      "completion": "Only a reconciled record with matching intent, commandId, auditId and reconciliation.evidence proves completion.",
      "workflow_id": "bridge_drain",
      "compatible_roles": [],
      "idempotency": "Caller supplies a stable idempotency_key for one intent. Reuse only with identical inputs. Never automatically retry an ambiguous POST.",
      "verify_operation": "getAdminCommand"
    },
    {
      "id": "postConfigPreflight",
      "method": "POST",
      "path": "/api/v1/admin/config/preflight",
      "summary": "Config preflight (HTTP fail-closed until RBAC/SSO; never completes on 2xx)",
      "required_role": "config_admin",
      "inputs": [
        {
          "name": "idempotency_key",
          "in": "query",
          "required": true,
          "schema": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          }
        },
        {
          "name": "expected_generation",
          "in": "query",
          "required": true,
          "schema": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20,
            "pattern": "^[0-9]+$"
          }
        },
        {
          "name": "expected_writer_term",
          "in": "query",
          "required": true,
          "schema": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20,
            "pattern": "^[0-9]+$"
          }
        },
        {
          "name": "target",
          "in": "query",
          "required": true,
          "schema": {
            "type": "string",
            "minLength": 1,
            "maxLength": 96,
            "pattern": "^[A-Za-z0-9._:@/-]+$"
          }
        }
      ],
      "side_effects": "Validate an existing staged reference; does not apply configuration.",
      "completion": "Only a reconciled record with matching intent, commandId, auditId and reconciliation.evidence proves completion.",
      "workflow_id": "config_preflight",
      "compatible_roles": [],
      "idempotency": "Caller supplies a stable idempotency_key for one intent. Reuse only with identical inputs. Never automatically retry an ambiguous POST.",
      "verify_operation": "getAdminCommand"
    },
    {
      "id": "getAdminCommand",
      "method": "GET",
      "path": "/api/v1/admin/commands/{id}",
      "summary": "Read-only observation of daemon-owned command lifecycle status",
      "required_role": "viewer",
      "inputs": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "side_effects": "None; read-only observation.",
      "completion": "Status observation only. HTTP 200 is not command completion; require reconciled with matching commandId, auditId and reconciliation.evidence."
    },
    {
      "id": "getAdminEvents",
      "method": "GET",
      "path": "/api/v1/admin/events",
      "summary": "Admin event frames (live GET via iot_admin_view events; fixtures remain)",
      "required_role": "viewer",
      "inputs": [
        {
          "name": "commandId",
          "in": "query",
          "required": false,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "offset",
          "in": "query",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 0,
            "default": 0
          }
        },
        {
          "name": "limit",
          "in": "query",
          "required": false,
          "schema": {
            "type": "integer",
            "minimum": 1,
            "maximum": 200,
            "default": 50
          }
        }
      ],
      "side_effects": "None; read-only observation.",
      "completion": "A version-compatible response; assess its freshness and readiness independently."
    },
    {
      "id": "postSupportBundleCreate",
      "method": "POST",
      "path": "/api/v1/admin/support/bundle",
      "summary": "Create support bundle command (support_admin owner; operator_admin API v1 compatibility; accepted only)",
      "required_role": "support_admin",
      "inputs": [
        {
          "name": "idempotency_key",
          "in": "query",
          "required": true,
          "schema": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          }
        },
        {
          "name": "expected_generation",
          "in": "query",
          "required": true,
          "schema": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20,
            "pattern": "^[0-9]+$"
          }
        },
        {
          "name": "expected_writer_term",
          "in": "query",
          "required": true,
          "schema": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20,
            "pattern": "^[0-9]+$"
          }
        },
        {
          "name": "target",
          "in": "query",
          "required": true,
          "schema": {
            "type": "string",
            "minLength": 1,
            "maxLength": 96,
            "pattern": "^[A-Za-z0-9._:@/-]+$"
          }
        }
      ],
      "side_effects": "Create a redacted, mode-0600 support artifact; review before sharing.",
      "completion": "Only a reconciled record with matching intent, commandId, auditId and reconciliation.evidence proves completion.",
      "workflow_id": "support_bundle_create",
      "compatible_roles": [
        "operator_admin"
      ],
      "idempotency": "Caller supplies a stable idempotency_key for one intent. Reuse only with identical inputs. Never automatically retry an ambiguous POST.",
      "verify_operation": "getAdminCommand"
    }
  ],
  "read_access": "Verified viewer-or-higher, or the deployment-controlled local read-only boundary. Client-supplied role/principal assertions never grant authority.",
  "recovery": {
    "action": "recover",
    "stage": "verify",
    "reads": [
      "getAdminEvents",
      "getAdminCommand"
    ],
    "matching": [
      "commandType",
      "target",
      "idempotencyKey",
      "expectedGeneration",
      "expectedWriterTerm"
    ],
    "max_event_pages": 3,
    "events_per_page": 200,
    "max_status_candidates": 32,
    "default_budget_seconds": 30,
    "max_budget_seconds": 300,
    "requires_unique_match": true,
    "resubmits_commands": false,
    "not_found": "Preserve the intent; inspect audit/retention or verify an explicit command ID. Absence is not permission to resubmit."
  }
}
