{
  "dsl": "rest-automation",
  "version": "1.0",
  "description": "Machine-readable schema for the mercury-composable rest.yaml DSL (HTTP endpoint -> service/flow mapping). Mirrors rest-grammar.md. An AI agent should ingest this to author and validate rest.yaml deterministically. The authoritative HTTP-method set is RoutingEntry.VALID_METHODS; a CI drift test keeps this catalog in sync.",
  "source_of_truth": "system/platform-core/src/main/java/org/platformlambda/automation/config/RoutingEntry.java (VALID_METHODS)",
  "top_level": [
    { "key": "rest", "meaning": "list of HTTP endpoint entries" },
    { "key": "cors", "meaning": "reusable CORS configs, referenced by a rest entry's cors:" },
    { "key": "headers", "meaning": "reusable header-transform configs, referenced by headers:" },
    { "key": "static-content", "meaning": "optional static asset / filter config" }
  ],
  "rest_entry_fields": [
    { "field": "service", "required": true, "meaning": "function route, or [primary, secondary], or http(s):// URL (relay); use http.flow.adapter to bind a flow" },
    { "field": "methods", "required": true, "meaning": "list from http_methods (OPTIONS auto-added; do not list it)" },
    { "field": "url", "required": true, "meaning": "URI path; supports {param} variables and a trailing * wildcard (case-insensitive)" },
    { "field": "flow", "required": false, "meaning": "flow id (used with service: http.flow.adapter)" },
    { "field": "timeout", "required": false, "meaning": "duration like 30s (default 30s; clamped 1s-5m)" },
    { "field": "cors", "required": false, "meaning": "id of a cors entry (must exist)" },
    { "field": "headers", "required": false, "meaning": "id of a headers entry (must exist)" },
    { "field": "authentication", "required": false, "meaning": "a service route, or routing specs: 'default: svc' / 'header: svc' / 'header: value: svc'" },
    { "field": "upload", "required": false, "meaning": "true/false (default false) - enable multipart upload" },
    { "field": "tracing", "required": false, "meaning": "true/false (default false) - enable distributed tracing" },
    { "field": "trust_all_cert", "required": false, "meaning": "true/false - HTTPS relay only" },
    { "field": "url_rewrite", "required": false, "meaning": "list of exactly two strings [from, to] - HTTP(S) relay only" }
  ],
  "http_methods": ["GET", "PUT", "POST", "DELETE", "HEAD", "PATCH", "OPTIONS"],
  "http_methods_note": "OPTIONS is auto-added by the parser; user entries must not list it.",
  "binding_modes": [
    { "mode": "function", "config": "service: <function.route>", "behavior": "route the request to a composable function" },
    { "mode": "flow", "config": "service: http.flow.adapter + flow: <flow-id>", "behavior": "run an Event Script flow" },
    { "mode": "http-relay", "config": "service: https://host", "behavior": "proxy to an external URL (url_rewrite, trust_all_cert apply)" },
    { "mode": "ab-dual", "config": "service: [primary, secondary]", "behavior": "primary serves the response; secondary gets a copy" }
  ],
  "cors_block": { "fields": ["id", "options", "headers"], "rule": "each options/headers entry must be an 'Access-Control-*: value' line" },
  "headers_block": { "fields": ["id", "request", "response"], "transforms": ["add", "drop", "keep"], "rule": "add entries are 'header-name: value'; drop/keep are header names (case-insensitive); keep retains only the listed headers" },
  "invariants": [
    "every rest entry has service, methods, and url",
    "methods values come from http_methods; OPTIONS is auto-added (do not list it)",
    "a cors:/headers: reference must match an existing cors/headers id",
    "url_rewrite is a list of exactly two strings; url_rewrite and trust_all_cert apply only to http(s):// relay services",
    "an HTTP-relay service must be a single URL (not a list, not mixed with function routes)",
    "flow binding uses service: http.flow.adapter"
  ]
}
