{
  "$defs": {
    "policy.cache": {
      "additionalProperties": false,
      "description": "Public response cache policy, declared under `policies.definitions` with `type: cache` and attached by a chain; looked up in the `request` phase. Applies to `GET` and `HEAD` only; its `when` condition is kept (for instance `!has(auth.subject)`). An authenticated cache is declared by the operation (`x-flexway-cache`), never by a policy.",
      "properties": {
        "scope": {
          "default": "public",
          "description": "Cache scope: `public` only (default). `subject` is refused here: it is declared in the operation's `x-flexway-cache`.",
          "enum": [
            "public"
          ],
          "type": "string",
          "x-flexway-description": {
            "en": "Cache scope: `public` only (default). `subject` is refused here: it is declared in the operation's `x-flexway-cache`.",
            "fr": "Portée du cache : `public` seulement (défaut). `subject` est refusé ici : il se déclare dans `x-flexway-cache` de l'opération."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        },
        "ttl": {
          "description": "How long a response is kept, a positive duration (`60s`); required.",
          "not": {
            "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
          },
          "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
          "type": "string",
          "x-flexway-description": {
            "en": "How long a response is kept, a positive duration (`60s`); required.",
            "fr": "Durée de conservation d'une réponse, durée positive (`60s`) ; obligatoire."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        }
      },
      "required": [
        "ttl"
      ],
      "type": "object",
      "x-flexway-description": {
        "en": "Public response cache policy, declared under `policies.definitions` with `type: cache` and attached by a chain; looked up in the `request` phase. Applies to `GET` and `HEAD` only; its `when` condition is kept (for instance `!has(auth.subject)`). An authenticated cache is declared by the operation (`x-flexway-cache`), never by a policy.",
        "fr": "Politique de cache de réponses publiques, déclarée sous `policies.definitions` avec `type: cache` et attachée par une chaîne ; consultée à la phase `request`. Ne vaut que pour `GET` et `HEAD` ; sa condition `when` est gardée (par exemple `!has(auth.subject)`). Un cache authentifié se déclare par l'opération (`x-flexway-cache`), jamais par une politique."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.2.0"
    },
    "policy.cors": {
      "additionalProperties": false,
      "description": "CORS policy, declared under `policies.definitions` with `type: cors`, attached globally, per host, per route or per operation; `request` phase, no `when` condition. Closed by default: an origin not listed is refused.",
      "properties": {
        "allow_credentials": {
          "description": "Allows browser requests with credentials (`Access-Control-Allow-Credentials`). Default `false`; refused with the `*` origin.",
          "type": "boolean",
          "x-flexway-description": {
            "en": "Allows browser requests with credentials (`Access-Control-Allow-Credentials`). Default `false`; refused with the `*` origin.",
            "fr": "Autorise les requêtes du navigateur avec identifiants (`Access-Control-Allow-Credentials`). Défaut `false` ; refusé avec l'origine `*`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.3.0"
        },
        "allow_headers": {
          "description": "Request headers allowed beside the ones the operation declares. Empty: the operation's own whitelist only.",
          "items": {
            "type": "string"
          },
          "type": "array",
          "x-flexway-description": {
            "en": "Request headers allowed beside the ones the operation declares. Empty: the operation's own whitelist only.",
            "fr": "En-têtes de requête autorisés en plus de ceux que l'opération déclare. Vide : la liste blanche de l'opération seule."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.3.0"
        },
        "allow_methods": {
          "description": "Methods announced in the preflight answer. Empty: the methods the contract declares for the path.",
          "items": {
            "type": "string"
          },
          "type": "array",
          "x-flexway-description": {
            "en": "Methods announced in the preflight answer. Empty: the methods the contract declares for the path.",
            "fr": "Méthodes annoncées en réponse au préliminaire. Vide : les méthodes que le contrat déclare pour le chemin."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.3.0"
        },
        "allow_origins": {
          "description": "Allowed origins (`https://app.example.com`), at least one; `*` admits any origin but never with `allow_credentials`.",
          "items": {
            "type": "string"
          },
          "minItems": 1,
          "type": "array",
          "x-flexway-description": {
            "en": "Allowed origins (`https://app.example.com`), at least one; `*` admits any origin but never with `allow_credentials`.",
            "fr": "Origines autorisées (`https://app.example.com`), au moins une ; `*` admet toute origine mais jamais avec `allow_credentials`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.3.0"
        },
        "expose_headers": {
          "description": "Response headers the browser lets the script read (`Access-Control-Expose-Headers`).",
          "items": {
            "type": "string"
          },
          "type": "array",
          "x-flexway-description": {
            "en": "Response headers the browser lets the script read (`Access-Control-Expose-Headers`).",
            "fr": "En-têtes de réponse que le navigateur laisse lire au script (`Access-Control-Expose-Headers`)."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.3.0"
        },
        "max_age": {
          "description": "How long the browser keeps the preflight answer (`Access-Control-Max-Age`), a positive duration (`10m`); absent: the header is not sent.",
          "not": {
            "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
          },
          "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
          "type": "string",
          "x-flexway-description": {
            "en": "How long the browser keeps the preflight answer (`Access-Control-Max-Age`), a positive duration (`10m`); absent: the header is not sent.",
            "fr": "Durée pendant laquelle le navigateur garde la réponse au préliminaire (`Access-Control-Max-Age`), durée positive (`10m`) ; absente : en-tête non envoyé."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.3.0"
        }
      },
      "required": [
        "allow_origins"
      ],
      "type": "object",
      "x-flexway-description": {
        "en": "CORS policy, declared under `policies.definitions` with `type: cors`, attached globally, per host, per route or per operation; `request` phase, no `when` condition. Closed by default: an origin not listed is refused.",
        "fr": "Politique CORS, déclarée sous `policies.definitions` avec `type: cors`, attachée globalement, par hôte, par route ou par opération ; phase `request`, sans condition `when`. Fermée par défaut : une origine non listée est refusée."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.3.0"
    },
    "policy.external-call": {
      "additionalProperties": false,
      "description": "Call to a declared service whose answer may refuse the request (`deny`) or set headers (`set_headers`), nothing else; `type: external-call` under `policies.definitions`, `request` phase (default, before the upstream) or `response`. Timeout and `on_failure` are required, the operation's budget is consumed; a simulated request calls nothing.",
      "properties": {
        "deny": {
          "additionalProperties": false,
          "description": "Refuses the request when a condition holds on the external service's answer; `when`, `status` and `code` are all required. At least one of `deny` or `set_headers` is needed.",
          "properties": {
            "code": {
              "description": "Error code of the problem served, `^[a-z][a-z0-9_]{0,63}$`; never one of the gateway's own codes (`forbidden`, `rate_limited`...).",
              "pattern": "^[a-z][a-z0-9_]{0,63}$",
              "type": "string",
              "x-flexway-description": {
                "en": "Error code of the problem served, `^[a-z][a-z0-9_]{0,63}$`; never one of the gateway's own codes (`forbidden`, `rate_limited`...).",
                "fr": "Code d'erreur du problème servi, `^[a-z][a-z0-9_]{0,63}$` ; jamais un code propre à la passerelle (`forbidden`, `rate_limited`...)."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.2.0"
            },
            "status": {
              "description": "Status of the refusal: a registered 4xx, other than 401, 405, 407 and 416.",
              "maximum": 499,
              "minimum": 400,
              "type": "integer",
              "x-flexway-description": {
                "en": "Status of the refusal: a registered 4xx, other than 401, 405, 407 and 416.",
                "fr": "Statut du refus : un 4xx enregistré, hors 401, 405, 407 et 416."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.2.0"
            },
            "when": {
              "description": "CEL condition on `response.status` and `response.body` - the external service's answer, never the upstream's.",
              "type": "string",
              "x-flexway-description": {
                "en": "CEL condition on `response.status` and `response.body` - the external service's answer, never the upstream's.",
                "fr": "Condition CEL sur `response.status` et `response.body` - la réponse du service externe, jamais celle de l'amont."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.2.0"
            }
          },
          "required": [
            "code",
            "status",
            "when"
          ],
          "type": "object",
          "x-flexway-description": {
            "en": "Refuses the request when a condition holds on the external service's answer; `when`, `status` and `code` are all required. At least one of `deny` or `set_headers` is needed.",
            "fr": "Refus de la requête quand une condition tient sur la réponse du service externe ; `when`, `status` et `code` tous obligatoires. Il faut au moins `deny` ou `set_headers`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        },
        "on_failure": {
          "description": "What happens without a usable answer (timeout, error, open breaker): `fail-open` goes on as if the policy did not apply, `fail-closed` refuses. Required, no default.",
          "enum": [
            "fail-open",
            "fail-closed"
          ],
          "type": "string",
          "x-flexway-description": {
            "en": "What happens without a usable answer (timeout, error, open breaker): `fail-open` goes on as if the policy did not apply, `fail-closed` refuses. Required, no default.",
            "fr": "Ce qui se passe sans réponse exploitable (délai, erreur, coupe-circuit) : `fail-open` continue comme si la politique ne s'appliquait pas, `fail-closed` refuse. Obligatoire, sans défaut."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        },
        "path": {
          "description": "Path called on the upstream, a literal starting with `/`, without `?`, `#`, `{`, `}` or space.",
          "pattern": "^/[^?#{} ]*$",
          "type": "string",
          "x-flexway-description": {
            "en": "Path called on the upstream, a literal starting with `/`, without `?`, `#`, `{`, `}` or space.",
            "fr": "Chemin appelé sur l'amont, littéral commençant par `/`, sans `?`, `#`, `{`, `}` ni espace."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        },
        "send": {
          "additionalProperties": false,
          "description": "What the call sends to the external service; nothing by default.",
          "properties": {
            "body": {
              "description": "Sends the request's body. Refused in the `response` phase, where it is already relayed.",
              "type": "boolean",
              "x-flexway-description": {
                "en": "Sends the request's body. Refused in the `response` phase, where it is already relayed.",
                "fr": "Envoie le corps de la requête. Refusé à la phase `response`, où il est déjà relayé."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.2.0"
            },
            "headers": {
              "description": "Headers of the request prepared for the upstream to send along (declared headers, the tenant written by the gateway); 32 at most. Never an undeclared header of the caller.",
              "items": {
                "type": "string"
              },
              "maxItems": 32,
              "type": "array",
              "x-flexway-description": {
                "en": "Headers of the request prepared for the upstream to send along (declared headers, the tenant written by the gateway); 32 at most. Never an undeclared header of the caller.",
                "fr": "En-têtes de la requête préparée pour l'amont à transmettre (en-têtes déclarés, tenant écrit par la passerelle) ; 32 au plus. Jamais un en-tête non déclaré de l'appelant."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.2.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "What the call sends to the external service; nothing by default.",
            "fr": "Ce que l'appel envoie au service externe ; rien par défaut."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        },
        "set_headers": {
          "additionalProperties": {
            "type": "string"
          },
          "description": "Headers set from the external answer: name -> CEL expression on `response`; 32 at most, values of 4,096 bytes at most (beyond, the call failed). Protected headers are refused.",
          "type": "object",
          "x-flexway-description": {
            "en": "Headers set from the external answer: name -> CEL expression on `response`; 32 at most, values of 4,096 bytes at most (beyond, the call failed). Protected headers are refused.",
            "fr": "En-têtes posés à partir de la réponse externe : nom -> expression CEL sur `response` ; 32 au plus, valeur de 4 096 octets au plus (au-delà, l'appel a échoué). En-têtes protégés refusés."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        },
        "timeout": {
          "description": "Timeout of the call, a positive duration (`200ms`); required. The call also consumes the operation's budget.",
          "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
          "type": "string",
          "x-flexway-description": {
            "en": "Timeout of the call, a positive duration (`200ms`); required. The call also consumes the operation's budget.",
            "fr": "Délai de l'appel, durée positive (`200ms`) ; obligatoire. L'appel consomme aussi le budget de l'opération."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        },
        "upstream": {
          "description": "Upstream called, declared in `upstreams`, over HTTP and without `token_exchange`; required.",
          "type": "string",
          "x-flexway-description": {
            "en": "Upstream called, declared in `upstreams`, over HTTP and without `token_exchange`; required.",
            "fr": "Amont appelé, déclaré dans `upstreams`, en HTTP et sans `token_exchange` ; obligatoire."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        }
      },
      "required": [
        "on_failure",
        "path",
        "timeout",
        "upstream"
      ],
      "type": "object",
      "x-flexway-description": {
        "en": "Call to a declared service whose answer may refuse the request (`deny`) or set headers (`set_headers`), nothing else; `type: external-call` under `policies.definitions`, `request` phase (default, before the upstream) or `response`. Timeout and `on_failure` are required, the operation's budget is consumed; a simulated request calls nothing.",
        "fr": "Appel à un service déclaré dont la réponse peut refuser la requête (`deny`) ou poser des en-têtes (`set_headers`), rien d'autre ; `type: external-call` sous `policies.definitions`, phase `request` (défaut, avant l'amont) ou `response`. Délai et `on_failure` obligatoires, le budget de l'opération est consommé ; une requête simulée n'appelle rien."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.2.0"
    },
    "policy.header-inject": {
      "additionalProperties": false,
      "description": "Sets or renames headers; `type: header-inject` under `policies.definitions`, `request` phase (default), `response` or `error`, optional `when` condition. Protected headers (identity, forwarding, tracing, hop-by-hop, `flexway-*`, the tenant header) are refused.",
      "properties": {
        "on_missing": {
          "description": "What a template does when its value is missing: `skip` (header not set), `empty` (set empty) or `fail` (request refused). Required as soon as a value is an expression; `skip` otherwise.",
          "enum": [
            "skip",
            "empty",
            "fail"
          ],
          "type": "string",
          "x-flexway-description": {
            "en": "What a template does when its value is missing: `skip` (header not set), `empty` (set empty) or `fail` (request refused). Required as soon as a value is an expression; `skip` otherwise.",
            "fr": "Ce que fait un gabarit dont la valeur manque : `skip` (en-tête non posé), `empty` (posé vide) ou `fail` (requête refusée). Obligatoire dès qu'une valeur est une expression ; `skip` sinon."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.5.0"
        },
        "rename": {
          "additionalProperties": {
            "type": "string"
          },
          "description": "Headers renamed: old name -> new name, values kept.",
          "type": "object",
          "x-flexway-description": {
            "en": "Headers renamed: old name -> new name, values kept.",
            "fr": "En-têtes renommés : ancien nom -> nouveau nom, valeurs gardées."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.5.0"
        },
        "set": {
          "additionalProperties": {
            "type": "string"
          },
          "description": "Headers set: name -> value, literal or a `{{ CEL expression }}` template (`{{ auth.claims.plan }}`); an existing value is replaced. At least one of `set` or `rename`.",
          "type": "object",
          "x-flexway-description": {
            "en": "Headers set: name -> value, literal or a `{{ CEL expression }}` template (`{{ auth.claims.plan }}`); an existing value is replaced. At least one of `set` or `rename`.",
            "fr": "En-têtes posés : nom -> valeur, littérale ou gabarit `{{ expression CEL }}` (`{{ auth.claims.plan }}`) ; une valeur existante est remplacée. Au moins `set` ou `rename`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.5.0"
        }
      },
      "type": "object",
      "x-flexway-description": {
        "en": "Sets or renames headers; `type: header-inject` under `policies.definitions`, `request` phase (default), `response` or `error`, optional `when` condition. Protected headers (identity, forwarding, tracing, hop-by-hop, `flexway-*`, the tenant header) are refused.",
        "fr": "Pose ou renomme des en-têtes ; `type: header-inject` sous `policies.definitions`, phase `request` (défaut), `response` ou `error`, condition `when` possible. Les en-têtes protégés (identité, transfert, traçage, saut par saut, `flexway-*`, en-tête du tenant) sont refusés."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.5.0"
    },
    "policy.header-remove": {
      "additionalProperties": false,
      "description": "Removes headers; `type: header-remove` under `policies.definitions`, `request` phase (default), `response` or `error`. Protected headers are refused.",
      "properties": {
        "names": {
          "description": "Names of the headers removed, at least one.",
          "items": {
            "type": "string"
          },
          "minItems": 1,
          "type": "array",
          "x-flexway-description": {
            "en": "Names of the headers removed, at least one.",
            "fr": "Noms des en-têtes retirés, au moins un."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.5.0"
        }
      },
      "required": [
        "names"
      ],
      "type": "object",
      "x-flexway-description": {
        "en": "Removes headers; `type: header-remove` under `policies.definitions`, `request` phase (default), `response` or `error`. Protected headers are refused.",
        "fr": "Retire des en-têtes ; `type: header-remove` sous `policies.definitions`, phase `request` (défaut), `response` ou `error`. Les en-têtes protégés sont refusés."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.5.0"
    },
    "policy.map-status": {
      "description": "Turns an upstream response's status into a semantic one; `type: map-status` under `policies.definitions`, `response` phase. Its configuration is a list of 1 to 64 rules `{ from, to, when, code }`, the first that applies wins; a rule after an unconditional rule with the same `from` is refused.",
      "items": {
        "additionalProperties": false,
        "properties": {
          "code": {
            "description": "Error code of the problem served, only when `to` is 400 or more; `^[a-z][a-z0-9_]{0,63}$`, never one of the gateway's own codes.",
            "pattern": "^[a-z][a-z0-9_]{0,63}$",
            "type": "string",
            "x-flexway-description": {
              "en": "Error code of the problem served, only when `to` is 400 or more; `^[a-z][a-z0-9_]{0,63}$`, never one of the gateway's own codes.",
              "fr": "Code d'erreur du problème servi, seulement quand `to` est 400 ou plus ; `^[a-z][a-z0-9_]{0,63}$`, jamais un code propre à la passerelle."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "1.2.0"
          },
          "from": {
            "description": "Upstream status matched, from 200 to 599; required.",
            "maximum": 599,
            "minimum": 200,
            "type": "integer",
            "x-flexway-description": {
              "en": "Upstream status matched, from 200 to 599; required.",
              "fr": "Statut de l'amont visé, de 200 à 599 ; obligatoire."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "1.2.0"
          },
          "to": {
            "description": "Status served, required: 200 or more, with an RFC 9110 reason, different from `from`, never a 3xx nor 204, 205, 206, 304, 401, 405, 407, 416 or 426.",
            "maximum": 599,
            "minimum": 200,
            "type": "integer",
            "x-flexway-description": {
              "en": "Status served, required: 200 or more, with an RFC 9110 reason, different from `from`, never a 3xx nor 204, 205, 206, 304, 401, 405, 407, 416 or 426.",
              "fr": "Statut servi, obligatoire : 200 ou plus, avec une raison RFC 9110, différent de `from`, jamais un 3xx ni 204, 205, 206, 304, 401, 405, 407, 416 ou 426."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "1.2.0"
          },
          "when": {
            "description": "Optional CEL condition, which may read `body`, the response's JSON body.",
            "type": "string",
            "x-flexway-description": {
              "en": "Optional CEL condition, which may read `body`, the response's JSON body.",
              "fr": "Condition CEL facultative, qui peut lire `body`, le corps JSON de la réponse."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "1.2.0"
          }
        },
        "required": [
          "from",
          "to"
        ],
        "type": "object"
      },
      "maxItems": 64,
      "minItems": 1,
      "type": "array",
      "x-flexway-description": {
        "en": "Turns an upstream response's status into a semantic one; `type: map-status` under `policies.definitions`, `response` phase. Its configuration is a list of 1 to 64 rules `{ from, to, when, code }`, the first that applies wins; a rule after an unconditional rule with the same `from` is refused.",
        "fr": "Change le statut d'une réponse de l'amont en statut sémantique ; `type: map-status` sous `policies.definitions`, phase `response`. Sa configuration est une liste de 1 à 64 règles `{ from, to, when, code }`, la première qui s'applique gagne ; une règle après une règle sans condition de même `from` est refusée."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.2.0"
    },
    "policy.query-inject": {
      "additionalProperties": false,
      "description": "Sets query parameters; `type: query-inject` under `policies.definitions`, `request` phase.",
      "properties": {
        "on_missing": {
          "description": "What a template does when its value is missing: `skip`, `empty` or `fail`. Required as soon as a value is an expression; `skip` otherwise.",
          "enum": [
            "skip",
            "empty",
            "fail"
          ],
          "type": "string",
          "x-flexway-description": {
            "en": "What a template does when its value is missing: `skip`, `empty` or `fail`. Required as soon as a value is an expression; `skip` otherwise.",
            "fr": "Ce que fait un gabarit dont la valeur manque : `skip`, `empty` ou `fail`. Obligatoire dès qu'une valeur est une expression ; `skip` sinon."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.5.0"
        },
        "set": {
          "additionalProperties": {
            "type": "string"
          },
          "description": "Parameters set: name -> value, literal or a `{{ CEL expression }}` template; at least one.",
          "type": "object",
          "x-flexway-description": {
            "en": "Parameters set: name -> value, literal or a `{{ CEL expression }}` template; at least one.",
            "fr": "Paramètres posés : nom -> valeur, littérale ou gabarit `{{ expression CEL }}` ; au moins un."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.5.0"
        }
      },
      "required": [
        "set"
      ],
      "type": "object",
      "x-flexway-description": {
        "en": "Sets query parameters; `type: query-inject` under `policies.definitions`, `request` phase.",
        "fr": "Pose des paramètres de requête ; `type: query-inject` sous `policies.definitions`, phase `request`."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.5.0"
    },
    "policy.query-remove": {
      "additionalProperties": false,
      "description": "Removes query parameters; `type: query-remove` under `policies.definitions`, `request` phase.",
      "properties": {
        "names": {
          "description": "Names of the parameters removed, at least one.",
          "items": {
            "type": "string"
          },
          "minItems": 1,
          "type": "array",
          "x-flexway-description": {
            "en": "Names of the parameters removed, at least one.",
            "fr": "Noms des paramètres retirés, au moins un."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.5.0"
        }
      },
      "required": [
        "names"
      ],
      "type": "object",
      "x-flexway-description": {
        "en": "Removes query parameters; `type: query-remove` under `policies.definitions`, `request` phase.",
        "fr": "Retire des paramètres de requête ; `type: query-remove` sous `policies.definitions`, phase `request`."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.5.0"
    },
    "policy.quota": {
      "additionalProperties": false,
      "description": "A tenant's request quota over calendar windows, UTC (day, month); `type: quota` under `policies.definitions`, `request` phase, no condition. Requires `server.counters`: counted in memory, a monthly quota would start again at every deployment. Beyond it: `429 quota_exceeded`.",
      "properties": {
        "key": {
          "default": "tenant",
          "description": "What is counted: `tenant` only (default).",
          "enum": [
            "tenant"
          ],
          "type": "string",
          "x-flexway-description": {
            "en": "What is counted: `tenant` only (default).",
            "fr": "Ce qui est compté : `tenant` seulement (défaut)."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.0.0"
        },
        "limits": {
          "additionalProperties": {
            "minimum": 1,
            "type": "integer"
          },
          "description": "Limits by window: `day` and/or `month`, each an integer of at least 1; at least one window.",
          "propertyNames": {
            "enum": [
              "day",
              "month"
            ]
          },
          "type": "object",
          "x-flexway-description": {
            "en": "Limits by window: `day` and/or `month`, each an integer of at least 1; at least one window.",
            "fr": "Plafonds par fenêtre : `day` et/ou `month`, chacun un entier d'au moins 1 ; au moins une fenêtre."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.0.0"
        }
      },
      "required": [
        "limits"
      ],
      "type": "object",
      "x-flexway-description": {
        "en": "A tenant's request quota over calendar windows, UTC (day, month); `type: quota` under `policies.definitions`, `request` phase, no condition. Requires `server.counters`: counted in memory, a monthly quota would start again at every deployment. Beyond it: `429 quota_exceeded`.",
        "fr": "Quota de requêtes d'un tenant sur des fenêtres calendaires UTC (jour, mois) ; `type: quota` sous `policies.definitions`, phase `request`, sans condition. Exige `server.counters` : compté en mémoire, un quota mensuel repartirait à chaque déploiement. Au-delà : `429 quota_exceeded`."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.0.0"
    },
    "policy.rate-limit": {
      "additionalProperties": false,
      "description": "Token buckets per caller; `type: rate-limit` under `policies.definitions`, `request` phase, no condition. An operation takes the class `read` (GET, HEAD, OPTIONS) or `write`, or the one of `x-flexway-rate-class`; beyond it: `429 rate_limited`.",
      "properties": {
        "classes": {
          "additionalProperties": {
            "additionalProperties": false,
            "properties": {
              "burst": {
                "description": "Bucket size: requests admitted at once; an integer of at least 1, required.",
                "minimum": 1,
                "type": "integer",
                "x-flexway-description": {
                  "en": "Bucket size: requests admitted at once; an integer of at least 1, required.",
                  "fr": "Taille du seau : requêtes admises d'un coup ; entier d'au moins 1, obligatoire."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.4.0"
              },
              "rps": {
                "description": "Bucket refill, in requests per second; a number greater than 0, required.",
                "exclusiveMinimum": 0,
                "type": "number",
                "x-flexway-description": {
                  "en": "Bucket refill, in requests per second; a number greater than 0, required.",
                  "fr": "Remplissage du seau, en requêtes par seconde ; nombre strictement positif, obligatoire."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.4.0"
              },
              "scope": {
                "description": "Overrides the policy's `scope` for this class: `class` or `operation`.",
                "enum": [
                  "class",
                  "operation"
                ],
                "type": "string",
                "x-flexway-description": {
                  "en": "Overrides the policy's `scope` for this class: `class` or `operation`.",
                  "fr": "Remplace `scope` de la politique pour cette classe : `class` ou `operation`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.0.0"
              }
            },
            "required": [
              "burst",
              "rps"
            ],
            "type": "object"
          },
          "description": "Rate classes by name (`read`, `write`, or your own), each a bucket; at least one.",
          "type": "object",
          "x-flexway-description": {
            "en": "Rate classes by name (`read`, `write`, or your own), each a bucket; at least one.",
            "fr": "Classes de débit par nom (`read`, `write`, ou les vôtres), chacune un seau ; au moins une."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.4.0"
        },
        "header": {
          "description": "With `key: header`, the header whose value keys an anonymous caller.",
          "type": "string",
          "x-flexway-description": {
            "en": "With `key: header`, the header whose value keys an anonymous caller.",
            "fr": "Avec `key: header`, l'en-tête dont la valeur sert de clé pour un appelant anonyme."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.0.0"
        },
        "key": {
          "default": "caller",
          "description": "What a bucket counts: `caller` (default) - the authenticated subject, else the client address - or `header` - for an anonymous caller, the value of `header`, believed only from a peer whose identity is in `trusted`. An authenticated subject stays the key either way.",
          "enum": [
            "caller",
            "header"
          ],
          "type": "string",
          "x-flexway-description": {
            "en": "What a bucket counts: `caller` (default) - the authenticated subject, else the client address - or `header` - for an anonymous caller, the value of `header`, believed only from a peer whose identity is in `trusted`. An authenticated subject stays the key either way.",
            "fr": "Ce qu'un seau compte : `caller` (défaut) - le sujet authentifié, sinon l'adresse du client - ou `header` - pour un anonyme, la valeur de `header`, crue seulement d'un pair dont l'identité figure dans `trusted`. Un sujet authentifié reste la clé dans les deux cas."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.4.0"
        },
        "scope": {
          "default": "class",
          "description": "What one bucket spans: `class` (default) - one bucket per caller and class, shared by the class's operations - or `operation` - one bucket per caller and operation, the class giving its size.",
          "enum": [
            "class",
            "operation"
          ],
          "type": "string",
          "x-flexway-description": {
            "en": "What one bucket spans: `class` (default) - one bucket per caller and class, shared by the class's operations - or `operation` - one bucket per caller and operation, the class giving its size.",
            "fr": "Ce qu'un seau couvre : `class` (défaut) - un seau par appelant et par classe, partagé par les opérations de la classe - ou `operation` - un seau par appelant et par opération, la classe en donnant la taille."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.0.0"
        },
        "trusted": {
          "description": "With `key: header`, the verified peer identities (through `server.peer_identity_header`) whose key header is believed; required with `key: header`.",
          "items": {
            "type": "string"
          },
          "type": "array",
          "x-flexway-description": {
            "en": "With `key: header`, the verified peer identities (through `server.peer_identity_header`) whose key header is believed; required with `key: header`.",
            "fr": "Avec `key: header`, les identités de pair vérifiées (par `server.peer_identity_header`) dont l'en-tête clé est cru ; obligatoire avec `key: header`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.0.0"
        }
      },
      "required": [
        "classes"
      ],
      "type": "object",
      "x-flexway-description": {
        "en": "Token buckets per caller; `type: rate-limit` under `policies.definitions`, `request` phase, no condition. An operation takes the class `read` (GET, HEAD, OPTIONS) or `write`, or the one of `x-flexway-rate-class`; beyond it: `429 rate_limited`.",
        "fr": "Seaux à jetons par appelant ; `type: rate-limit` sous `policies.definitions`, phase `request`, sans condition. Une opération prend la classe `read` (GET, HEAD, OPTIONS) ou `write`, ou celle de `x-flexway-rate-class` ; au-delà : `429 rate_limited`."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.4.0"
    },
    "policy.redact": {
      "additionalProperties": false,
      "description": "Masks or removes fields of the response's JSON body; `type: redact` under `policies.definitions`, `response` phase. Exactly one of `with` or `remove: true`.",
      "properties": {
        "fields": {
          "description": "Field paths, starting with `body.` (`body.card.number`), segments `[A-Za-z_][A-Za-z0-9_]*`; 1 to 256 paths, 32 segments at most, no duplicate.",
          "items": {
            "pattern": "^body\\.",
            "type": "string"
          },
          "maxItems": 256,
          "minItems": 1,
          "type": "array",
          "x-flexway-description": {
            "en": "Field paths, starting with `body.` (`body.card.number`), segments `[A-Za-z_][A-Za-z0-9_]*`; 1 to 256 paths, 32 segments at most, no duplicate.",
            "fr": "Chemins des champs, commençant par `body.` (`body.card.number`), segments `[A-Za-z_][A-Za-z0-9_]*` ; 1 à 256 chemins, 32 segments au plus, sans doublon."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        },
        "remove": {
          "description": "`true` removes the fields instead of masking them; never with `with`.",
          "type": "boolean",
          "x-flexway-description": {
            "en": "`true` removes the fields instead of masking them; never with `with`.",
            "fr": "`true` retire les champs au lieu de les masquer ; jamais avec `with`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        },
        "with": {
          "description": "Value a masked field is replaced by: a string, a number, a boolean or `null`; never with `remove: true`.",
          "type": [
            "string",
            "number",
            "boolean",
            "null"
          ],
          "x-flexway-description": {
            "en": "Value a masked field is replaced by: a string, a number, a boolean or `null`; never with `remove: true`.",
            "fr": "Valeur qui remplace un champ masqué : une chaîne, un nombre, un booléen ou `null` ; jamais avec `remove: true`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        }
      },
      "required": [
        "fields"
      ],
      "type": "object",
      "x-flexway-description": {
        "en": "Masks or removes fields of the response's JSON body; `type: redact` under `policies.definitions`, `response` phase. Exactly one of `with` or `remove: true`.",
        "fr": "Masque ou retire des champs du corps JSON de la réponse ; `type: redact` sous `policies.definitions`, phase `response`. Exactement un de `with` ou `remove: true`."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.2.0"
    },
    "policy.rewrite-path": {
      "additionalProperties": false,
      "description": "Points the request at another path on the upstream; `type: rewrite-path` under `policies.definitions`, `request` phase.",
      "properties": {
        "to": {
          "description": "Upstream path, starting with `/`; `{param}` takes the value of a route parameter, escaped, never the raw text of the path received.",
          "pattern": "^/",
          "type": "string",
          "x-flexway-description": {
            "en": "Upstream path, starting with `/`; `{param}` takes the value of a route parameter, escaped, never the raw text of the path received.",
            "fr": "Chemin de l'amont, commençant par `/` ; `{param}` y prend la valeur d'un paramètre de la route, échappée, jamais le texte brut du chemin reçu."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.5.0"
        }
      },
      "required": [
        "to"
      ],
      "type": "object",
      "x-flexway-description": {
        "en": "Points the request at another path on the upstream; `type: rewrite-path` under `policies.definitions`, `request` phase.",
        "fr": "Dirige la requête vers un autre chemin de l'amont ; `type: rewrite-path` sous `policies.definitions`, phase `request`."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.5.0"
    },
    "policy.transform-body": {
      "additionalProperties": false,
      "description": "Closed projection of the response's JSON body: only the fields listed are served; `type: transform-body` under `policies.definitions`, `response` phase. Body bounded by `server.body.max_bytes`.",
      "properties": {
        "on_missing": {
          "description": "Projected field absent from the response: `fail` (response refused) or `omit` (field left out). Required.",
          "enum": [
            "fail",
            "omit"
          ],
          "type": "string",
          "x-flexway-description": {
            "en": "Projected field absent from the response: `fail` (response refused) or `omit` (field left out). Required.",
            "fr": "Champ projeté absent de la réponse : `fail` (réponse refusée) ou `omit` (champ omis). Obligatoire."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        },
        "project": {
          "description": "Dotted paths of the fields kept (`id`, `customer.name`), segments `[A-Za-z_][A-Za-z0-9_]*`; 1 to 256 paths, 32 segments at most.",
          "items": {
            "type": "string"
          },
          "maxItems": 256,
          "minItems": 1,
          "type": "array",
          "x-flexway-description": {
            "en": "Dotted paths of the fields kept (`id`, `customer.name`), segments `[A-Za-z_][A-Za-z0-9_]*`; 1 to 256 paths, 32 segments at most.",
            "fr": "Chemins pointés des champs gardés (`id`, `customer.name`), segments `[A-Za-z_][A-Za-z0-9_]*` ; 1 à 256 chemins, 32 segments au plus."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        }
      },
      "required": [
        "on_missing",
        "project"
      ],
      "type": "object",
      "x-flexway-description": {
        "en": "Closed projection of the response's JSON body: only the fields listed are served; `type: transform-body` under `policies.definitions`, `response` phase. Body bounded by `server.body.max_bytes`.",
        "fr": "Projection fermée du corps JSON de la réponse : seuls les champs listés sont servis ; `type: transform-body` sous `policies.definitions`, phase `response`. Corps borné par `server.body.max_bytes`."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.2.0"
    }
  },
  "$id": "https://flexway.io/schema/v1/flexway.schema.json",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "additionalProperties": false,
  "description": "The gateway's configuration file: it says how things are served, never what. It lists no operation - it references the contracts and describes upstreams, hosts, identities and policies. Decoding is strict: an unknown key is refused, and every problem is reported at once.",
  "properties": {
    "agents": {
      "additionalProperties": false,
      "description": "What agents reach: the MCP surface, the bounds of delegation chains and A2A governance. No tool is listed here: an operation becomes a tool in the contract (`x-flexway-tool`).",
      "properties": {
        "a2a": {
          "additionalProperties": false,
          "description": "The deployment's side of A2A governance: what the declared agent cards (`contracts.a2a`) do not say.",
          "properties": {
            "push": {
              "additionalProperties": false,
              "description": "Guard of the push notification targets a caller hands an upstream agent. Absent or empty: every push notification configuration is refused - closed by default.",
              "properties": {
                "allowed_hosts": {
                  "description": "Host names a push notification may target: an exact name, or `*.domain` for its subdomains, each with an optional `:port`, in lower case. Never an IP address, a bare `*` or `localhost`; a duplicate entry is refused.",
                  "items": {
                    "type": "string"
                  },
                  "type": "array",
                  "x-flexway-description": {
                    "en": "Host names a push notification may target: an exact name, or `*.domain` for its subdomains, each with an optional `:port`, in lower case. Never an IP address, a bare `*` or `localhost`; a duplicate entry is refused.",
                    "fr": "Noms d'hôtes qu'une notification push peut viser : nom exact ou `*.domaine` pour ses sous-domaines, chacun avec un `:port` facultatif, en minuscules. Jamais une adresse IP, ni `*` seul, ni `localhost` ; une entrée en double est refusée."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.2.0"
                }
              },
              "type": "object",
              "x-flexway-description": {
                "en": "Guard of the push notification targets a caller hands an upstream agent. Absent or empty: every push notification configuration is refused - closed by default.",
                "fr": "Garde des cibles de notification push qu'un appelant confie à un agent amont. Absente ou vide : toute configuration de notification push est refusée - fermé par défaut."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.2.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "The deployment's side of A2A governance: what the declared agent cards (`contracts.a2a`) do not say.",
            "fr": "La part du déploiement dans la gouvernance A2A : ce que les cartes d'agents déclarées (`contracts.a2a`) ne disent pas."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        },
        "delegation": {
          "additionalProperties": false,
          "description": "Bounds the chains of agents acting for a person (RFC 8693 `act` claim) and lets a revocation break them. Absent: a delegated token is accepted like any other. When set, every issuer of `auth.issuers` must declare `client`, for introspection.",
          "properties": {
            "introspection": {
              "additionalProperties": false,
              "description": "How a revocation is seen: delegated tokens are introspected at their issuer (RFC 7662).",
              "properties": {
                "cache": {
                  "default": "10s",
                  "description": "How long an introspection answer is reused - the longest a revoked chain keeps working. A duration (`10s`); default `10s`.",
                  "not": {
                    "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
                  },
                  "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "How long an introspection answer is reused - the longest a revoked chain keeps working. A duration (`10s`); default `10s`.",
                    "fr": "Durée de réutilisation d'une réponse d'introspection - le plus long délai pendant lequel une chaîne révoquée fonctionne encore. Durée (`10s`) ; défaut `10s`."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "0.7.0"
                }
              },
              "type": "object",
              "x-flexway-description": {
                "en": "How a revocation is seen: delegated tokens are introspected at their issuer (RFC 7662).",
                "fr": "Comment une révocation est vue : les jetons délégués sont introspectés auprès de leur émetteur (RFC 7662)."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.7.0"
            },
            "max_age": {
              "default": "15m",
              "description": "Maximum age of a chain, counted from the person's authentication (`auth_time`, else `iat`). A duration (`15m`); default `15m`. A contract may tighten it per operation, never widen it.",
              "not": {
                "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
              },
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "Maximum age of a chain, counted from the person's authentication (`auth_time`, else `iat`). A duration (`15m`); default `15m`. A contract may tighten it per operation, never widen it.",
                "fr": "Âge maximal d'une chaîne, compté depuis l'authentification de la personne (`auth_time`, sinon `iat`). Durée (`15m`) ; défaut `15m`. Un contrat peut le resserrer par opération, jamais l'élargir."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.7.0"
            },
            "max_depth": {
              "default": 2,
              "description": "How many agents a chain may hold. A non-negative integer; `0` accepts no delegated token; default `2`. A contract may tighten it per operation, never widen it.",
              "minimum": 0,
              "type": "integer",
              "x-flexway-description": {
                "en": "How many agents a chain may hold. A non-negative integer; `0` accepts no delegated token; default `2`. A contract may tighten it per operation, never widen it.",
                "fr": "Nombre d'agents qu'une chaîne peut contenir. Entier positif ou nul ; `0` n'accepte aucun jeton délégué ; défaut `2`. Un contrat peut le resserrer par opération, jamais l'élargir."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.7.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "Bounds the chains of agents acting for a person (RFC 8693 `act` claim) and lets a revocation break them. Absent: a delegated token is accepted like any other. When set, every issuer of `auth.issuers` must declare `client`, for introspection.",
            "fr": "Borne les chaînes d'agents agissant pour une personne (claim `act` de la RFC 8693) et permet à une révocation de les rompre. Absent : un jeton délégué est accepté comme un autre. Présent, chaque émetteur de `auth.issuers` doit déclarer `client`, pour l'introspection."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.7.0"
        },
        "mcp": {
          "additionalProperties": false,
          "description": "The Model Context Protocol surface: where it is served, and as what resource. Operations marked `x-flexway-tool` are offered there as tools under the same decision as REST; the token received is never relayed upstream.",
          "properties": {
            "clients": {
              "description": "When set, the only OAuth clients admitted on the surface, named by the URL of their Client ID Metadata Document: an exact `https` URL, or a prefix ending with `/*`. Absent: any client.",
              "items": {
                "type": "string"
              },
              "type": "array",
              "x-flexway-description": {
                "en": "When set, the only OAuth clients admitted on the surface, named by the URL of their Client ID Metadata Document: an exact `https` URL, or a prefix ending with `/*`. Absent: any client.",
                "fr": "Quand il est renseigné, seuls clients OAuth admis sur la surface, nommés par l'URL de leur document de métadonnées client : URL `https` exacte, ou préfixe se terminant par `/*`. Absent : tout client."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.0.0"
            },
            "path": {
              "default": "/mcp",
              "description": "Path the MCP surface answers on, on every host of `resources`. A literal path starting with `/`, without `{`, `}` or `*`; default `/mcp`.",
              "type": "string",
              "x-flexway-description": {
                "en": "Path the MCP surface answers on, on every host of `resources`. A literal path starting with `/`, without `{`, `}` or `*`; default `/mcp`.",
                "fr": "Chemin où la surface MCP répond, sur chaque hôte de `resources`. Chemin littéral commençant par `/`, sans `{`, `}` ni `*` ; défaut `/mcp`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.7.0"
            },
            "resources": {
              "additionalProperties": {
                "type": "string"
              },
              "description": "Maps each host that serves the surface to its public URL - the audience a token must carry to be accepted there (RFC 8707). An absolute `https` URL (`http` for localhost only), without query or fragment, ending in `path`. Required and non-empty; declared, never derived from the request.",
              "type": "object",
              "x-flexway-description": {
                "en": "Maps each host that serves the surface to its public URL - the audience a token must carry to be accepted there (RFC 8707). An absolute `https` URL (`http` for localhost only), without query or fragment, ending in `path`. Required and non-empty; declared, never derived from the request.",
                "fr": "Associe chaque hôte qui sert la surface à son URL publique - l'audience qu'un jeton doit porter pour y être accepté (RFC 8707). URL absolue `https` (`http` pour localhost seulement), sans requête ni fragment, terminée par `path`. Obligatoire et non vide ; déclarée, jamais déduite de la requête."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.7.0"
            },
            "servers": {
              "additionalProperties": {
                "additionalProperties": false,
                "properties": {
                  "discovery": {
                    "additionalProperties": false,
                    "description": "How the server's tools are listed. Discovery runs in the background and never blocks the start.",
                    "properties": {
                      "issuer": {
                        "description": "Name of an issuer of `auth.issuers`, with a `client`, from which the gateway obtains a `client_credentials` token to list the tools - for a server that requires a token even for that. Absent: listed anonymously.",
                        "type": "string",
                        "x-flexway-description": {
                          "en": "Name of an issuer of `auth.issuers`, with a `client`, from which the gateway obtains a `client_credentials` token to list the tools - for a server that requires a token even for that. Absent: listed anonymously.",
                          "fr": "Nom d'un émetteur de `auth.issuers`, doté d'un `client`, dont la passerelle obtient un jeton `client_credentials` pour lister les outils - pour un serveur qui exige un jeton même pour cela. Absent : listés anonymement."
                        },
                        "x-flexway-reloadable": true,
                        "x-flexway-since": "0.7.0"
                      },
                      "refresh": {
                        "default": "5m",
                        "description": "How often the tools are listed again. A duration (`5m`); default `5m`.",
                        "not": {
                          "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
                        },
                        "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
                        "type": "string",
                        "x-flexway-description": {
                          "en": "How often the tools are listed again. A duration (`5m`); default `5m`.",
                          "fr": "Fréquence à laquelle les outils sont listés à nouveau. Durée (`5m`) ; défaut `5m`."
                        },
                        "x-flexway-reloadable": true,
                        "x-flexway-since": "0.7.0"
                      }
                    },
                    "type": "object",
                    "x-flexway-description": {
                      "en": "How the server's tools are listed. Discovery runs in the background and never blocks the start.",
                      "fr": "Comment les outils du serveur sont listés. La découverte tourne en arrière-plan et ne bloque jamais le démarrage."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "0.7.0"
                  },
                  "hosts": {
                    "description": "MCP surfaces (hosts of `agents.mcp.resources`) that serve this server. Empty: every surface.",
                    "items": {
                      "type": "string"
                    },
                    "type": "array",
                    "x-flexway-description": {
                      "en": "MCP surfaces (hosts of `agents.mcp.resources`) that serve this server. Empty: every surface.",
                      "fr": "Surfaces MCP (hôtes de `agents.mcp.resources`) qui servent ce serveur. Vide : toutes les surfaces."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "0.7.0"
                  },
                  "rate_classes": {
                    "additionalProperties": {
                      "type": "string"
                    },
                    "description": "A tool's rate-limit class, by original name (a served tool). Otherwise `read` when the server announces the tool read-only, `write` otherwise.",
                    "type": "object",
                    "x-flexway-description": {
                      "en": "A tool's rate-limit class, by original name (a served tool). Otherwise `read` when the server announces the tool read-only, `write` otherwise.",
                      "fr": "Classe de débit d'un outil, par nom d'origine (outil servi). Sinon `read` quand le serveur annonce l'outil en lecture seule, `write` autrement."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "0.7.0"
                  },
                  "rename": {
                    "additionalProperties": {
                      "type": "string"
                    },
                    "description": "Gives a tool another name on the surface, by original name - against a collision, for instance. The tool must be in `tools`.",
                    "type": "object",
                    "x-flexway-description": {
                      "en": "Gives a tool another name on the surface, by original name - against a collision, for instance. The tool must be in `tools`.",
                      "fr": "Donne à un outil un autre nom sur la surface, par nom d'origine - contre une collision par exemple. L'outil doit figurer dans `tools`."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "0.7.0"
                  },
                  "scopes": {
                    "description": "Scopes required for every tool of the server. Empty: an authenticated caller is enough.",
                    "items": {
                      "type": "string"
                    },
                    "type": "array",
                    "x-flexway-description": {
                      "en": "Scopes required for every tool of the server. Empty: an authenticated caller is enough.",
                      "fr": "Portées exigées pour chaque outil du serveur. Vide : un appelant authentifié suffit."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "0.7.0"
                  },
                  "tool_scopes": {
                    "additionalProperties": {
                      "items": {
                        "type": "string"
                      },
                      "type": "array"
                    },
                    "description": "Replaces `scopes` for one tool, by original name; the tool must be in `tools`.",
                    "type": "object",
                    "x-flexway-description": {
                      "en": "Replaces `scopes` for one tool, by original name; the tool must be in `tools`.",
                      "fr": "Remplace `scopes` pour un outil, par nom d'origine ; l'outil doit figurer dans `tools`."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "0.7.0"
                  },
                  "tools": {
                    "anyOf": [
                      {
                        "const": "*"
                      },
                      {
                        "items": {
                          "type": "string"
                        },
                        "type": "array"
                      }
                    ],
                    "description": "Tools served: a declared list of names - the closed default - or `\"*\"` for whatever the server announces, chosen explicitly. Required.",
                    "x-flexway-description": {
                      "en": "Tools served: a declared list of names - the closed default - or `\"*\"` for whatever the server announces, chosen explicitly. Required.",
                      "fr": "Outils servis : une liste de noms déclarée - le choix fermé par défaut - ou `\"*\"` pour tout ce que le serveur annonce, choisi explicitement. Obligatoire."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "0.7.0"
                  },
                  "upstream": {
                    "description": "Name of an upstream of `upstreams` with `protocol: mcp`: where the server is, with the pool, budgets, breaker, bulkhead and token exchange that come with it. Required.",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "Name of an upstream of `upstreams` with `protocol: mcp`: where the server is, with the pool, budgets, breaker, bulkhead and token exchange that come with it. Required.",
                      "fr": "Nom d'un amont de `upstreams` de `protocol: mcp` : où est le serveur, avec le pool, les budgets, le coupe-circuit, le cloisonnement et l'échange de jeton qui vont avec. Obligatoire."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "0.7.0"
                  }
                },
                "required": [
                  "tools",
                  "upstream"
                ],
                "type": "object"
              },
              "description": "Existing MCP servers whose tools the surface serves too (federation), under their original names, with the gateway's authorization, quota and metrics in front. The key names the server.",
              "type": "object",
              "x-flexway-description": {
                "en": "Existing MCP servers whose tools the surface serves too (federation), under their original names, with the gateway's authorization, quota and metrics in front. The key names the server.",
                "fr": "Serveurs MCP existants dont les outils sont servis aussi par la surface (fédération), sous leurs noms d'origine, avec l'autorisation, le quota et les métriques de la passerelle. La clé nomme le serveur."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.7.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "The Model Context Protocol surface: where it is served, and as what resource. Operations marked `x-flexway-tool` are offered there as tools under the same decision as REST; the token received is never relayed upstream.",
            "fr": "Surface Model Context Protocol : où elle est servie et pour quelle ressource. Les opérations marquées `x-flexway-tool` y sont offertes en outils sous la même décision que REST ; le jeton reçu n'est jamais relayé à l'amont."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.7.0"
        }
      },
      "type": "object",
      "x-flexway-description": {
        "en": "What agents reach: the MCP surface, the bounds of delegation chains and A2A governance. No tool is listed here: an operation becomes a tool in the contract (`x-flexway-tool`).",
        "fr": "Ce que les agents atteignent : la surface MCP, les bornes des chaînes de délégation et la gouvernance A2A. Aucun outil n'est listé ici : une opération devient un outil dans le contrat (`x-flexway-tool`)."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.7.0"
    },
    "ai": {
      "additionalProperties": false,
      "description": "The inference surface `/v1/*` (OpenAI-compatible) served by the data plane, routed by policy to backends, under per-tenant token and euro budgets. Absent: not served. No contract to write: its operations are built in.",
      "properties": {
        "backends": {
          "additionalProperties": {
            "additionalProperties": false,
            "properties": {
              "api_key": {
                "description": "The backend's key, sent as a `Bearer` token - a reference (`${VAR}` or `file:/path`), read at each use. Empty for a keyless internal backend. Exclusive with `auth` (equivalent to `auth: { scheme: bearer, key: ... }`).",
                "pattern": "^(\\$\\{[A-Za-z_][A-Za-z0-9_]*\\}|file:/\\S+)$",
                "type": "string",
                "x-flexway-description": {
                  "en": "The backend's key, sent as a `Bearer` token - a reference (`${VAR}` or `file:/path`), read at each use. Empty for a keyless internal backend. Exclusive with `auth` (equivalent to `auth: { scheme: bearer, key: ... }`).",
                  "fr": "Clé du backend, envoyée en jeton `Bearer` - une référence (`${VAR}` ou `file:/chemin`), lue à chaque usage. Vide pour un backend interne sans clé. Exclusive de `auth` (équivaut à `auth: { scheme: bearer, key: ... }`)."
                },
                "x-flexway-reference": true,
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.8.0"
              },
              "auth": {
                "additionalProperties": false,
                "description": "How the gateway authenticates to the backend, exactly one scheme. Absent: `api_key` as a `Bearer` token, else none.",
                "properties": {
                  "header": {
                    "description": "Name of the header the key is sent in: the `header` scheme only, and required there.",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "Name of the header the key is sent in: the `header` scheme only, and required there.",
                      "fr": "Nom de l'en-tête qui porte la clé : schéma `header` seulement, et alors obligatoire."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "1.5.0"
                  },
                  "key": {
                    "description": "The key sent, by reference (`${VAR}` or `file:/path`), read again at each call: the `bearer` and `header` schemes. Never a key in clear.",
                    "pattern": "^(\\$\\{[A-Za-z_][A-Za-z0-9_]*\\}|file:/\\S+)$",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "The key sent, by reference (`${VAR}` or `file:/path`), read again at each call: the `bearer` and `header` schemes. Never a key in clear.",
                      "fr": "Clé envoyée, par référence (`${VAR}` ou `file:/chemin`), relue à chaque appel : schémas `bearer` et `header`. Jamais une clé en clair."
                    },
                    "x-flexway-reference": true,
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "1.5.0"
                  },
                  "path": {
                    "description": "File a short-lived token is read from at each call, as a workload identity projects it; sent as a `Bearer` token. The `token_file` scheme only, and required there.",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "File a short-lived token is read from at each call, as a workload identity projects it; sent as a `Bearer` token. The `token_file` scheme only, and required there.",
                      "fr": "Fichier d'où un jeton de courte durée est lu à chaque appel, tel qu'une identité de charge de travail le projette ; envoyé en jeton `Bearer`. Schéma `token_file` seulement, et alors obligatoire."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "1.5.0"
                  },
                  "scheme": {
                    "description": "Authentication scheme: `none` (nothing), `bearer` (`Authorization: Bearer <key>`), `header` (the key in the `header` header), `token_file` (a token read from `path`). Required in `auth`.",
                    "enum": [
                      "none",
                      "bearer",
                      "header",
                      "token_file"
                    ],
                    "type": "string",
                    "x-flexway-description": {
                      "en": "Authentication scheme: `none` (nothing), `bearer` (`Authorization: Bearer <key>`), `header` (the key in the `header` header), `token_file` (a token read from `path`). Required in `auth`.",
                      "fr": "Schéma d'authentification : `none` (rien), `bearer` (`Authorization: Bearer <key>`), `header` (la clé dans l'en-tête `header`), `token_file` (un jeton lu dans `path`). Obligatoire dans `auth`."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "1.5.0"
                  }
                },
                "required": [
                  "scheme"
                ],
                "type": "object",
                "x-flexway-description": {
                  "en": "How the gateway authenticates to the backend, exactly one scheme. Absent: `api_key` as a `Bearer` token, else none.",
                  "fr": "Comment la passerelle s'authentifie auprès du backend, un seul schéma. Absent : `api_key` en jeton `Bearer`, sinon aucune."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.5.0"
              },
              "capabilities": {
                "description": "What the backend serves: `chat`, `vision` (serves text too), `embeddings`, `model` (a specialised model, `grpc` backends only). No duplicate. Empty: `chat`, or `model` for a `grpc` backend.",
                "items": {
                  "enum": [
                    "chat",
                    "vision",
                    "embeddings",
                    "model"
                  ],
                  "type": "string"
                },
                "type": "array",
                "x-flexway-description": {
                  "en": "What the backend serves: `chat`, `vision` (serves text too), `embeddings`, `model` (a specialised model, `grpc` backends only). No duplicate. Empty: `chat`, or `model` for a `grpc` backend.",
                  "fr": "Ce que sert le backend : `chat`, `vision` (sert aussi le texte), `embeddings`, `model` (modèle spécialisé d'un backend `grpc` seulement). Sans doublon. Vide : `chat`, ou `model` pour un backend `grpc`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.5.0"
              },
              "default_model": {
                "description": "Model served when the caller asks for none of `models`. Required, except for a `relay` (the gateway it relays to chooses) and a `grpc` backend.",
                "type": "string",
                "x-flexway-description": {
                  "en": "Model served when the caller asks for none of `models`. Required, except for a `relay` (the gateway it relays to chooses) and a `grpc` backend.",
                  "fr": "Modèle servi quand l'appelant n'en demande pas un de `models`. Obligatoire, sauf pour un `relay` (la passerelle relayée choisit) et un `grpc`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.8.0"
              },
              "external": {
                "description": "Marks a third party: a sensitive request never goes there. A boolean; unset: `false`, except for a `relay`, external unless the operator declares `external: false`.",
                "type": "boolean",
                "x-flexway-description": {
                  "en": "Marks a third party: a sensitive request never goes there. A boolean; unset: `false`, except for a `relay`, external unless the operator declares `external: false`.",
                  "fr": "Marque un tiers : une requête sensible n'y va jamais. Booléen ; non renseigné : `false`, sauf pour un `relay`, externe tant que l'exploitant ne déclare pas `external: false`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.8.0"
              },
              "fallback": {
                "description": "Backends tried in turn when this one fails before answering (connection, `5xx`, timeout, open breaker), each once; never on a `4xx`, nor after a stream's first byte, nor to an external backend for a sensitive request. Names of `ai.backends`, not itself, no duplicate, never a `grpc` backend.",
                "items": {
                  "type": "string"
                },
                "type": "array",
                "x-flexway-description": {
                  "en": "Backends tried in turn when this one fails before answering (connection, `5xx`, timeout, open breaker), each once; never on a `4xx`, nor after a stream's first byte, nor to an external backend for a sensitive request. Names of `ai.backends`, not itself, no duplicate, never a `grpc` backend.",
                  "fr": "Backends essayés tour à tour quand celui-ci échoue avant de répondre (connexion, `5xx`, délai, coupe-circuit ouvert), chacun une fois ; jamais sur un `4xx`, ni après le premier octet d'un flux, ni vers un externe pour une requête sensible. Noms de `ai.backends`, sans lui-même, sans doublon, jamais un `grpc`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.8.0"
              },
              "identity_headers": {
                "additionalProperties": false,
                "description": "Header names a `relay` backend receives the call's tenant, agent and sensitivity under - those the other gateway declares in `auth.trusted_headers` and `ai.sensitive_header`. For the `relay` kind only, where `tenant` is required.",
                "properties": {
                  "agent": {
                    "description": "Name of the header carrying the calling agent toward the relay. Optional.",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "Name of the header carrying the calling agent toward the relay. Optional.",
                      "fr": "Nom de l'en-tête qui porte l'agent appelant vers le relais. Facultatif."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "1.5.0"
                  },
                  "sensitive": {
                    "description": "Name of the header carrying the call's sensitivity toward the relay. Optional.",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "Name of the header carrying the call's sensitivity toward the relay. Optional.",
                      "fr": "Nom de l'en-tête qui porte la sensibilité de l'appel vers le relais. Facultatif."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "1.5.0"
                  },
                  "tenant": {
                    "description": "Name of the header carrying the call's real tenant toward the relay. Required for a `relay`: the gateway it reaches must see the real tenant, not a single caller.",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "Name of the header carrying the call's real tenant toward the relay. Required for a `relay`: the gateway it reaches must see the real tenant, not a single caller.",
                      "fr": "Nom de l'en-tête qui porte le tenant réel de l'appel vers le relais. Obligatoire pour un `relay` : la passerelle relayée doit voir le vrai tenant, pas un seul appelant."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "1.5.0"
                  }
                },
                "type": "object",
                "x-flexway-description": {
                  "en": "Header names a `relay` backend receives the call's tenant, agent and sensitivity under - those the other gateway declares in `auth.trusted_headers` and `ai.sensitive_header`. For the `relay` kind only, where `tenant` is required.",
                  "fr": "Noms d'en-têtes sous lesquels un backend `relay` reçoit le tenant, l'agent et la sensibilité de l'appel - ceux que l'autre passerelle déclare dans `auth.trusted_headers` et `ai.sensitive_header`. Réservé au genre `relay`, où `tenant` est obligatoire."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.5.0"
              },
              "kind": {
                "default": "openai",
                "description": "Backend kind: `openai` (any OpenAI-compatible API, the default), `relay` (another Flexway, spoken to as OpenAI with the call's identity under declared headers), `grpc` (a specialised model served by a method of a gRPC contract, never a target of `/v1/*`).",
                "enum": [
                  "openai",
                  "relay",
                  "grpc"
                ],
                "type": "string",
                "x-flexway-description": {
                  "en": "Backend kind: `openai` (any OpenAI-compatible API, the default), `relay` (another Flexway, spoken to as OpenAI with the call's identity under declared headers), `grpc` (a specialised model served by a method of a gRPC contract, never a target of `/v1/*`).",
                  "fr": "Genre du backend : `openai` (toute API compatible OpenAI, défaut), `relay` (une autre Flexway, parlée en OpenAI avec l'identité de l'appel sous des en-têtes déclarés), `grpc` (modèle spécialisé servi par une méthode d'un contrat gRPC, jamais une cible de `/v1/*`)."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.5.0"
              },
              "metering": {
                "default": "local",
                "description": "Who counts the cost: `local` (the default, this gateway counts and caps) or `upstream` (the gateway it relays to counts; this one still applies its own local cap). `upstream` is refused on an `openai` backend.",
                "enum": [
                  "local",
                  "upstream"
                ],
                "type": "string",
                "x-flexway-description": {
                  "en": "Who counts the cost: `local` (the default, this gateway counts and caps) or `upstream` (the gateway it relays to counts; this one still applies its own local cap). `upstream` is refused on an `openai` backend.",
                  "fr": "Qui compte le coût : `local` (défaut, cette passerelle compte et plafonne) ou `upstream` (la passerelle relayée compte ; celle-ci applique toujours son propre plafond local). `upstream` est refusé sur un backend `openai`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.5.0"
              },
              "models": {
                "description": "Models a caller may ask for by name; any other is served `default_model`. No empty entry.",
                "items": {
                  "type": "string"
                },
                "type": "array",
                "x-flexway-description": {
                  "en": "Models a caller may ask for by name; any other is served `default_model`. No empty entry.",
                  "fr": "Modèles qu'un appelant peut demander par leur nom ; tout autre est servi par `default_model`. Aucune entrée vide."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.5.0"
              },
              "price": {
                "additionalProperties": false,
                "description": "Price of a million tokens, in euros, input and output apart; `0` is a price. Required as soon as a budget is counted in euros (except a `grpc` backend or one metered upstream).",
                "properties": {
                  "input_per_mtok": {
                    "description": "Price in euros of a million input tokens. A non-negative number.",
                    "minimum": 0,
                    "type": "number",
                    "x-flexway-description": {
                      "en": "Price in euros of a million input tokens. A non-negative number.",
                      "fr": "Prix en euros d'un million de tokens d'entrée. Nombre positif ou nul."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "0.8.0"
                  },
                  "output_per_mtok": {
                    "description": "Price in euros of a million output tokens. A non-negative number.",
                    "minimum": 0,
                    "type": "number",
                    "x-flexway-description": {
                      "en": "Price in euros of a million output tokens. A non-negative number.",
                      "fr": "Prix en euros d'un million de tokens de sortie. Nombre positif ou nul."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "0.8.0"
                  }
                },
                "type": "object",
                "x-flexway-description": {
                  "en": "Price of a million tokens, in euros, input and output apart; `0` is a price. Required as soon as a budget is counted in euros (except a `grpc` backend or one metered upstream).",
                  "fr": "Prix d'un million de tokens, en euros, entrée et sortie à part ; `0` est un prix. Obligatoire dès qu'un budget est compté en euros (sauf backend `grpc` ou mesuré en amont)."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.8.0"
              },
              "tls": {
                "additionalProperties": false,
                "description": "Client TLS toward the backend - a relay's mutual TLS -, as an upstream's. Only used with an `https://` URL.",
                "properties": {
                  "ca_file": {
                    "description": "PEM file of the authorities that verify the backend's certificate. Absent: the system's authorities.",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "PEM file of the authorities that verify the backend's certificate. Absent: the system's authorities.",
                      "fr": "Fichier PEM des autorités qui vérifient le certificat du backend. Absent : les autorités du système."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "1.5.0"
                  },
                  "cert_file": {
                    "description": "PEM client certificate presented to the backend; goes with `key_file`.",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "PEM client certificate presented to the backend; goes with `key_file`.",
                      "fr": "Certificat client PEM présenté au backend ; va avec `key_file`."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "1.5.0"
                  },
                  "key_file": {
                    "description": "PEM private key of the client certificate; goes with `cert_file`.",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "PEM private key of the client certificate; goes with `cert_file`.",
                      "fr": "Clé privée PEM du certificat client ; va avec `cert_file`."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "1.5.0"
                  },
                  "server_name": {
                    "description": "Name expected in the backend's certificate (SNI), when it differs from the URL's host.",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "Name expected in the backend's certificate (SNI), when it differs from the URL's host.",
                      "fr": "Nom attendu dans le certificat du backend (SNI), quand il diffère de l'hôte de l'URL."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "1.5.0"
                  }
                },
                "type": "object",
                "x-flexway-description": {
                  "en": "Client TLS toward the backend - a relay's mutual TLS -, as an upstream's. Only used with an `https://` URL.",
                  "fr": "TLS client vers le backend - le TLS mutuel d'un relais -, comme celui d'un amont. Ignoré tant que l'URL n'est pas `https://`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.5.0"
              },
              "upstream": {
                "description": "For a `grpc` backend only, and required there: name of an upstream with `protocol: grpc` that serves its methods. Such a backend carries no `url`, model, authentication nor price: its methods' (`x-flexway-ai`).",
                "type": "string",
                "x-flexway-description": {
                  "en": "For a `grpc` backend only, and required there: name of an upstream with `protocol: grpc` that serves its methods. Such a backend carries no `url`, model, authentication nor price: its methods' (`x-flexway-ai`).",
                  "fr": "Pour un backend `grpc` seulement, et alors obligatoire : nom d'un amont de `protocol: grpc` qui sert ses méthodes. Un tel backend ne porte ni `url`, ni modèle, ni authentification, ni prix : ceux de ses méthodes (`x-flexway-ai`)."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.5.0"
              },
              "url": {
                "description": "The backend's address: an absolute `http` or `https` URL (for instance `https://api.provider.example/v1`). Required, except for a `grpc` backend.",
                "type": "string",
                "x-flexway-description": {
                  "en": "The backend's address: an absolute `http` or `https` URL (for instance `https://api.provider.example/v1`). Required, except for a `grpc` backend.",
                  "fr": "Adresse du backend : URL absolue `http` ou `https` (par exemple `https://api.provider.example/v1`). Obligatoire, sauf pour un backend `grpc`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.8.0"
              }
            },
            "type": "object"
          },
          "description": "Inference backends, by name. At least one. A backend is declared by kind, capabilities, authentication and metering; no provider is named: a provider is a URL, an authentication and a price.",
          "type": "object",
          "x-flexway-description": {
            "en": "Inference backends, by name. At least one. A backend is declared by kind, capabilities, authentication and metering; no provider is named: a provider is a URL, an authentication and a price.",
            "fr": "Backends d'inférence, par nom. Au moins un. Un backend se déclare par genre (`kind`), capacités, authentification et mesure ; aucun fournisseur n'est nommé : un fournisseur est une URL, une authentification et un prix."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.8.0"
        },
        "budget": {
          "additionalProperties": false,
          "description": "The per-tenant inference budget, counted in a Redis-compatible shared cache (Redis, Dragonfly or Valkey) every replica uses.",
          "properties": {
            "daily_tokens": {
              "description": "Tokens per tenant and UTC day. A non-negative integer; `0`: no daily budget.",
              "type": "integer",
              "x-flexway-description": {
                "en": "Tokens per tenant and UTC day. A non-negative integer; `0`: no daily budget.",
                "fr": "Tokens par tenant et par jour UTC. Entier positif ou nul ; `0` : aucun budget journalier."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.8.0"
            },
            "monthly_eur": {
              "description": "Per-tenant budget in euros over the calendar month, at each backend's declared price. A non-negative number; `0`: none. Requires `price` on the backends.",
              "minimum": 0,
              "type": "number",
              "x-flexway-description": {
                "en": "Per-tenant budget in euros over the calendar month, at each backend's declared price. A non-negative number; `0`: none. Requires `price` on the backends.",
                "fr": "Budget par tenant en euros sur le mois civil, au prix déclaré de chaque backend. Nombre positif ou nul ; `0` : aucun. Exige `price` sur les backends."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.8.0"
            },
            "monthly_tokens": {
              "description": "Tokens per tenant and UTC calendar month. A non-negative integer; `0`: no monthly budget.",
              "type": "integer",
              "x-flexway-description": {
                "en": "Tokens per tenant and UTC calendar month. A non-negative integer; `0`: no monthly budget.",
                "fr": "Tokens par tenant et par mois civil UTC. Entier positif ou nul ; `0` : aucun budget mensuel."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.8.0"
            },
            "soft": {
              "additionalProperties": false,
              "description": "Soft cap: past `at` of the euro budget, the gateway warns (`Flexway-Budget: soft`, a metric, a log line) and routes to `backend` when set. Requires a euro budget (`monthly_eur`, or an override's).",
              "properties": {
                "at": {
                  "description": "Share of the euro budget past which the soft cap applies: a number in `(0, 1]` (for instance `0.8`).",
                  "maximum": 1,
                  "minimum": 0,
                  "type": "number",
                  "x-flexway-description": {
                    "en": "Share of the euro budget past which the soft cap applies: a number in `(0, 1]` (for instance `0.8`).",
                    "fr": "Part du budget en euros au-delà de laquelle le plafond souple s'applique : nombre dans `]0, 1]` (par exemple `0.8`)."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "0.8.0"
                },
                "backend": {
                  "description": "Backend of `ai.backends` to switch to past the soft cap - except a sensitive request, which stays pinned. Never a `grpc` backend. Absent: warn only.",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "Backend of `ai.backends` to switch to past the soft cap - except a sensitive request, which stays pinned. Never a `grpc` backend. Absent: warn only.",
                    "fr": "Backend de `ai.backends` vers lequel basculer au-delà du plafond souple - sauf une requête sensible, qui reste épinglée. Jamais un `grpc`. Absent : prévenir seulement."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "0.8.0"
                }
              },
              "type": "object",
              "x-flexway-description": {
                "en": "Soft cap: past `at` of the euro budget, the gateway warns (`Flexway-Budget: soft`, a metric, a log line) and routes to `backend` when set. Requires a euro budget (`monthly_eur`, or an override's).",
                "fr": "Plafond souple : passé `at` du budget en euros, la passerelle prévient (`Flexway-Budget: soft`, métrique, journal) et route vers `backend` s'il est renseigné. Exige un budget en euros (`monthly_eur` ou celui d'une surcharge)."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.8.0"
            },
            "store": {
              "description": "Shared cache of the budget counters: `redis://host:port` (or `rediss://`), or a reference (`${VAR}`, `file:/path`) as soon as it carries a password. Required.",
              "type": "string",
              "x-flexway-description": {
                "en": "Shared cache of the budget counters: `redis://host:port` (or `rediss://`), or a reference (`${VAR}`, `file:/path`) as soon as it carries a password. Required.",
                "fr": "Cache des compteurs de budget : `redis://hôte:port` (ou `rediss://`), ou une référence (`${VAR}`, `file:/chemin`) dès qu'il porte un mot de passe. Obligatoire."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.8.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "The per-tenant inference budget, counted in a Redis-compatible shared cache (Redis, Dragonfly or Valkey) every replica uses.",
            "fr": "Budget d'inférence par tenant, compté dans un cache partagé compatible Redis (Redis, Dragonfly ou Valkey), commun à toutes les répliques."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.8.0"
        },
        "default_backend": {
          "description": "Backend of `ai.backends` that serves a call no override routes elsewhere. Required; an `openai` or `relay` backend, never `grpc`.",
          "type": "string",
          "x-flexway-description": {
            "en": "Backend of `ai.backends` that serves a call no override routes elsewhere. Required; an `openai` or `relay` backend, never `grpc`.",
            "fr": "Backend de `ai.backends` qui sert un appel qu'aucune surcharge ne route ailleurs. Obligatoire ; un backend `openai` ou `relay`, jamais `grpc`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.8.0"
        },
        "overrides": {
          "description": "Route or budget one tenant, or one agent of it, differently; the first match wins. An override that names a capability only routes, never budgets.",
          "items": {
            "additionalProperties": false,
            "properties": {
              "backend": {
                "description": "Backend of `ai.backends` that serves the matching calls; never a `grpc` backend. Required when `match.capability` is set, and that backend must serve the capability.",
                "type": "string",
                "x-flexway-description": {
                  "en": "Backend of `ai.backends` that serves the matching calls; never a `grpc` backend. Required when `match.capability` is set, and that backend must serve the capability.",
                  "fr": "Backend de `ai.backends` qui sert les appels concernés ; jamais un `grpc`. Obligatoire quand `match.capability` est renseigné, et ce backend doit servir la capacité."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.8.0"
              },
              "daily_tokens": {
                "description": "Daily token budget of the matching tenant, in place of `ai.budget.daily_tokens`. A non-negative integer; refused with `match.capability`.",
                "type": "integer",
                "x-flexway-description": {
                  "en": "Daily token budget of the matching tenant, in place of `ai.budget.daily_tokens`. A non-negative integer; refused with `match.capability`.",
                  "fr": "Budget journalier en tokens du tenant concerné, à la place de `ai.budget.daily_tokens`. Entier positif ou nul ; interdit avec `match.capability`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.8.0"
              },
              "match": {
                "additionalProperties": false,
                "description": "What selects the calls: a tenant, an agent of it, a capability.",
                "properties": {
                  "agent": {
                    "description": "Calling agent (the call's subject) the override applies to, within `tenant`.",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "Calling agent (the call's subject) the override applies to, within `tenant`.",
                      "fr": "Agent appelant (le sujet de l'appel) à qui la surcharge s'applique, au sein de `tenant`."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "0.8.0"
                  },
                  "capability": {
                    "description": "Capability asked for: `chat`, `vision` or `embeddings`. Such an override only routes: it requires `backend` and refuses any budget.",
                    "enum": [
                      "chat",
                      "vision",
                      "embeddings"
                    ],
                    "type": "string",
                    "x-flexway-description": {
                      "en": "Capability asked for: `chat`, `vision` or `embeddings`. Such an override only routes: it requires `backend` and refuses any budget.",
                      "fr": "Capacité demandée : `chat`, `vision` ou `embeddings`. Une telle surcharge route seulement : elle exige `backend` et refuse tout budget."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "1.5.0"
                  },
                  "tenant": {
                    "description": "Tenant the override applies to.",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "Tenant the override applies to.",
                      "fr": "Tenant à qui la surcharge s'applique."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "0.8.0"
                  }
                },
                "type": "object",
                "x-flexway-description": {
                  "en": "What selects the calls: a tenant, an agent of it, a capability.",
                  "fr": "Ce qui sélectionne les appels : un tenant, un agent de ce tenant, une capacité."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.8.0"
              },
              "monthly_eur": {
                "description": "Monthly euro budget of the matching tenant, in place of `ai.budget.monthly_eur`. A non-negative number; requires `price` on the backends; refused with `match.capability`.",
                "type": "number",
                "x-flexway-description": {
                  "en": "Monthly euro budget of the matching tenant, in place of `ai.budget.monthly_eur`. A non-negative number; requires `price` on the backends; refused with `match.capability`.",
                  "fr": "Budget mensuel en euros du tenant concerné, à la place de `ai.budget.monthly_eur`. Nombre positif ou nul ; exige `price` sur les backends ; interdit avec `match.capability`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.8.0"
              },
              "monthly_tokens": {
                "description": "Monthly token budget of the matching tenant, in place of `ai.budget.monthly_tokens`. A non-negative integer; refused with `match.capability`.",
                "type": "integer",
                "x-flexway-description": {
                  "en": "Monthly token budget of the matching tenant, in place of `ai.budget.monthly_tokens`. A non-negative integer; refused with `match.capability`.",
                  "fr": "Budget mensuel en tokens du tenant concerné, à la place de `ai.budget.monthly_tokens`. Entier positif ou nul ; interdit avec `match.capability`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.8.0"
              }
            },
            "type": "object"
          },
          "type": "array",
          "x-flexway-description": {
            "en": "Route or budget one tenant, or one agent of it, differently; the first match wins. An override that names a capability only routes, never budgets.",
            "fr": "Routent ou budgètent autrement un tenant, ou un agent de ce tenant ; la première qui correspond gagne. Une surcharge qui nomme une capacité ne fait que router, jamais budgéter."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.8.0"
        },
        "security": {
          "description": "Identities `/v1/*` accepts, any one of which suffices - as `security` does in a contract. A non-empty list; each entry names exactly one mechanism: `trusted_headers`, `oidc`, `api_key` or `mtls`.",
          "items": {
            "additionalProperties": false,
            "maxProperties": 1,
            "minProperties": 1,
            "properties": {
              "api_key": {
                "additionalProperties": false,
                "description": "Accepts an API key (`{}`). Requires `auth.api_keys`.",
                "type": "object",
                "x-flexway-description": {
                  "en": "Accepts an API key (`{}`). Requires `auth.api_keys`.",
                  "fr": "Accepte une clé d'API (`{}`). Exige `auth.api_keys`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.8.0"
              },
              "mtls": {
                "additionalProperties": false,
                "description": "Accepts a declared client certificate (`{}`). Requires `auth.mtls`.",
                "type": "object",
                "x-flexway-description": {
                  "en": "Accepts a declared client certificate (`{}`). Requires `auth.mtls`.",
                  "fr": "Accepte un certificat client déclaré (`{}`). Exige `auth.mtls`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.8.0"
              },
              "oidc": {
                "additionalProperties": false,
                "description": "Accepts a token from an issuer of `auth.issuers`, with the scopes and roles required. Requires at least one issuer.",
                "properties": {
                  "roles": {
                    "description": "Roles the token must carry (read through its issuer's `roles_claim`).",
                    "items": {
                      "type": "string"
                    },
                    "type": "array",
                    "x-flexway-description": {
                      "en": "Roles the token must carry (read through its issuer's `roles_claim`).",
                      "fr": "Rôles que le jeton doit porter (lus par `roles_claim` de son émetteur)."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "0.8.0"
                  },
                  "scopes": {
                    "description": "Scopes the token must carry.",
                    "items": {
                      "type": "string"
                    },
                    "type": "array",
                    "x-flexway-description": {
                      "en": "Scopes the token must carry.",
                      "fr": "Portées que le jeton doit porter."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "0.8.0"
                  }
                },
                "type": "object",
                "x-flexway-description": {
                  "en": "Accepts a token from an issuer of `auth.issuers`, with the scopes and roles required. Requires at least one issuer.",
                  "fr": "Accepte un jeton d'un émetteur de `auth.issuers`, avec les portées et rôles exigés. Exige au moins un émetteur."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.8.0"
              },
              "trusted_headers": {
                "additionalProperties": false,
                "description": "Accepts the identity a trusted peer wrote into the headers of `auth.trusted_headers` (`{}`), believed from a peer of `server.trusted_proxies` only. Requires `auth.trusted_headers`.",
                "type": "object",
                "x-flexway-description": {
                  "en": "Accepts the identity a trusted peer wrote into the headers of `auth.trusted_headers` (`{}`), believed from a peer of `server.trusted_proxies` only. Requires `auth.trusted_headers`.",
                  "fr": "Accepte l'identité écrite par un pair de confiance dans les en-têtes de `auth.trusted_headers` (`{}`), crue d'un pair de `server.trusted_proxies` seulement. Exige `auth.trusted_headers`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.8.0"
              }
            },
            "type": "object"
          },
          "type": "array",
          "x-flexway-description": {
            "en": "Identities `/v1/*` accepts, any one of which suffices - as `security` does in a contract. A non-empty list; each entry names exactly one mechanism: `trusted_headers`, `oidc`, `api_key` or `mtls`.",
            "fr": "Identités que `/v1/*` accepte, dont une seule suffit - comme `security` dans un contrat. Liste non vide ; chaque entrée nomme exactement un mécanisme : `trusted_headers`, `oidc`, `api_key` ou `mtls`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.8.0"
        },
        "sensitive_backend": {
          "description": "Internal backend of `ai.backends` a sensitive request is pinned to. An external or `grpc` backend is refused; without one, a sensitive request is refused (`403`), never sent to an external backend.",
          "type": "string",
          "x-flexway-description": {
            "en": "Internal backend of `ai.backends` a sensitive request is pinned to. An external or `grpc` backend is refused; without one, a sensitive request is refused (`403`), never sent to an external backend.",
            "fr": "Backend interne de `ai.backends` où une requête sensible est épinglée. Un backend externe ou `grpc` est refusé ; sans lui, une requête sensible est refusée (`403`), jamais envoyée à un externe."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.8.0"
        },
        "sensitive_header": {
          "description": "Header that, set to `true` by a caller, pins the request to `sensitive_backend`. Believed from any caller: it can only make routing stricter. A header name (letters, digits, `-`).",
          "type": "string",
          "x-flexway-description": {
            "en": "Header that, set to `true` by a caller, pins the request to `sensitive_backend`. Believed from any caller: it can only make routing stricter. A header name (letters, digits, `-`).",
            "fr": "En-tête qui, mis à `true` par l'appelant, épingle la requête sur `sensitive_backend`. Cru de tout appelant : il ne peut que resserrer le routage. Nom d'en-tête (lettres, chiffres, `-`)."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.8.0"
        },
        "vision": {
          "additionalProperties": false,
          "description": "Bounds of the images of a chat completion. Absent: the defaults, and only inline `data:` images are accepted.",
          "properties": {
            "allowed_origins": {
              "description": "Origins (`https://host[:port]`, no path) an image may be given by URL from. Empty: inline `data:` images only. The gateway never fetches them: the backend does.",
              "items": {
                "type": "string"
              },
              "type": "array",
              "x-flexway-description": {
                "en": "Origins (`https://host[:port]`, no path) an image may be given by URL from. Empty: inline `data:` images only. The gateway never fetches them: the backend does.",
                "fr": "Origines (`https://hôte[:port]`, sans chemin) depuis lesquelles une image peut être donnée par URL. Vide : images `data:` en ligne seulement. La passerelle ne les télécharge jamais : le backend le fait."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.5.0"
            },
            "max_body_bytes": {
              "anyOf": [
                {
                  "minimum": 1,
                  "type": "integer"
                },
                {
                  "pattern": "^\\s*[1-9][0-9]*\\s*(B|KiB|MiB|GiB)?\\s*$",
                  "type": "string"
                }
              ],
              "description": "Bound of the body of a chat completion that carries images. A size (`24MiB`, or a number of bytes); default `24MiB`. A completion without image keeps `server.limits.max_body`. At least `max_image_bytes`.",
              "x-flexway-description": {
                "en": "Bound of the body of a chat completion that carries images. A size (`24MiB`, or a number of bytes); default `24MiB`. A completion without image keeps `server.limits.max_body`. At least `max_image_bytes`.",
                "fr": "Borne du corps d'une complétion qui porte des images. Taille (`24MiB`, ou un nombre d'octets) ; défaut `24MiB`. Une complétion sans image garde `server.limits.max_body`. Au moins `max_image_bytes`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.5.0"
            },
            "max_image_bytes": {
              "anyOf": [
                {
                  "minimum": 1,
                  "type": "integer"
                },
                {
                  "pattern": "^\\s*[1-9][0-9]*\\s*(B|KiB|MiB|GiB)?\\s*$",
                  "type": "string"
                }
              ],
              "description": "Bound of one image, decoded. A size (`8MiB`, or a number of bytes); default `8MiB`.",
              "x-flexway-description": {
                "en": "Bound of one image, decoded. A size (`8MiB`, or a number of bytes); default `8MiB`.",
                "fr": "Borne d'une image, une fois décodée. Taille (`8MiB`, ou un nombre d'octets) ; défaut `8MiB`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.5.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "Bounds of the images of a chat completion. Absent: the defaults, and only inline `data:` images are accepted.",
            "fr": "Bornes des images d'une complétion de chat. Absent : les défauts, et seules les images `data:` en ligne sont acceptées."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.5.0"
        }
      },
      "type": "object",
      "x-flexway-description": {
        "en": "The inference surface `/v1/*` (OpenAI-compatible) served by the data plane, routed by policy to backends, under per-tenant token and euro budgets. Absent: not served. No contract to write: its operations are built in.",
        "fr": "Surface d'inférence `/v1/*` (compatible OpenAI) servie par le plan de données, routée par politique vers des backends, sous des budgets de tokens et d'euros par tenant. Absente : non servie. Aucun contrat à écrire : ses opérations sont intégrées."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.8.0"
    },
    "audit": {
      "additionalProperties": false,
      "description": "Chained audit stream of the API plane's authorization decisions: each entry is linked to the previous one by a hash, so a rewrite shows.",
      "properties": {
        "decisions": {
          "description": "Which decisions are recorded: `all` (every one) or `refusals` (refusals only). Absent or empty: no decision is recorded.",
          "enum": [
            "all",
            "refusals"
          ],
          "type": "string",
          "x-flexway-description": {
            "en": "Which decisions are recorded: `all` (every one) or `refusals` (refusals only). Absent or empty: no decision is recorded.",
            "fr": "Décisions enregistrées : `all` (toutes) ou `refusals` (les refus seulement). Absente ou vide : aucune décision n'est enregistrée."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.0.0"
        },
        "key": {
          "description": "HMAC key of the chain and of the subject's digest, by reference (`${VAR}` or `file:/path`), never a literal. Without it, whoever can write the whole stream can rewrite it and recompute every hash. Read once at start.",
          "type": "string",
          "x-flexway-description": {
            "en": "HMAC key of the chain and of the subject's digest, by reference (`${VAR}` or `file:/path`), never a literal. Without it, whoever can write the whole stream can rewrite it and recompute every hash. Read once at start.",
            "fr": "Clé HMAC de la chaîne et de l'empreinte du sujet, par référence (`${VAR}` ou `file:/chemin`), jamais en clair. Sans elle, qui peut écrire tout le flux peut le réécrire et recalculer chaque empreinte. Lue une seule fois au démarrage."
          },
          "x-flexway-reloadable": false,
          "x-flexway-since": "1.0.0"
        }
      },
      "type": "object",
      "x-flexway-description": {
        "en": "Chained audit stream of the API plane's authorization decisions: each entry is linked to the previous one by a hash, so a rewrite shows.",
        "fr": "Journal d'audit chaîné des décisions d'autorisation du plan API : chaque entrée est liée à la précédente par une empreinte, ce qui rend une réécriture visible."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.0.0"
    },
    "auth": {
      "additionalProperties": false,
      "description": "How an identity is verified - never what an operation requires, which the contract declares (`security`): token issuers, API keys, client certificates, trusted headers.",
      "properties": {
        "api_keys": {
          "additionalProperties": false,
          "description": "Callers' API keys, an identity - never an authorization: what an operation requires stays in the contract (an `apiKey` scheme). A key satisfies only the alternative that names it and opens only its bound operations.",
          "properties": {
            "store": {
              "description": "File of the keys' digests: `file:` followed by a path, relative to the configuration file unless absolute, mounted from a secret. Never a key in clear; read again at each reload - removing an entry revokes the key.",
              "pattern": "^file:.+",
              "type": "string",
              "x-flexway-description": {
                "en": "File of the keys' digests: `file:` followed by a path, relative to the configuration file unless absolute, mounted from a secret. Never a key in clear; read again at each reload - removing an entry revokes the key.",
                "fr": "Fichier des empreintes des clés : `file:` suivi d'un chemin, relatif au fichier de configuration sauf s'il est absolu, monté depuis un secret. Jamais une clé en clair ; relu à chaque rechargement - retirer une entrée révoque la clé."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.7.0"
            }
          },
          "required": [
            "store"
          ],
          "type": "object",
          "x-flexway-description": {
            "en": "Callers' API keys, an identity - never an authorization: what an operation requires stays in the contract (an `apiKey` scheme). A key satisfies only the alternative that names it and opens only its bound operations.",
            "fr": "Clés d'API des appelants, une identité - jamais une autorisation : ce qu'une opération exige reste au contrat (schéma `apiKey`). La clé ne satisfait que l'alternative qui la nomme et n'ouvre que ses opérations liées."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.7.0"
        },
        "issuers": {
          "description": "Trusted token providers (OIDC), several at once: a customer usually has one for its employees and another for its end users. Two entries may not name the same issuer.",
          "items": {
            "additionalProperties": false,
            "properties": {
              "algorithms": {
                "default": [
                  "RS256",
                  "RS384",
                  "RS512",
                  "PS256",
                  "PS384",
                  "PS512",
                  "ES256",
                  "ES384",
                  "ES512",
                  "EdDSA"
                ],
                "description": "Signature algorithms accepted. Default: the asymmetric family (`RS256` to `RS512`, `PS256` to `PS512`, `ES256` to `ES512`, `EdDSA`). `none` and the HMAC family (`HS*`) are refused at load.",
                "items": {
                  "not": {
                    "pattern": "^([Nn][Oo][Nn][Ee]|[Hh][Ss][0-9]+)$"
                  },
                  "type": "string"
                },
                "type": "array",
                "x-flexway-description": {
                  "en": "Signature algorithms accepted. Default: the asymmetric family (`RS256` to `RS512`, `PS256` to `PS512`, `ES256` to `ES512`, `EdDSA`). `none` and the HMAC family (`HS*`) are refused at load.",
                  "fr": "Algorithmes de signature acceptés. Défaut : la famille asymétrique (`RS256` à `RS512`, `PS256` à `PS512`, `ES256` à `ES512`, `EdDSA`). `none` et la famille HMAC (`HS*`) sont refusés au chargement."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.3.0"
              },
              "audience": {
                "description": "Audience a token must be issued for, checked together with the issuer. Required unless `audiences` is used; exclusive with `audiences`.",
                "type": "string",
                "x-flexway-description": {
                  "en": "Audience a token must be issued for, checked together with the issuer. Required unless `audiences` is used; exclusive with `audiences`.",
                  "fr": "Audience pour laquelle un jeton doit être émis, vérifiée avec l'émetteur. Obligatoire sauf si `audiences` est utilisé ; exclusive de `audiences`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.3.0"
              },
              "audiences": {
                "description": "Instead of `audience`, accepts a token issued for any one of them - while an API renames its audience. No empty entry; exclusive with `audience`.",
                "items": {
                  "type": "string"
                },
                "type": "array",
                "x-flexway-description": {
                  "en": "Instead of `audience`, accepts a token issued for any one of them - while an API renames its audience. No empty entry; exclusive with `audience`.",
                  "fr": "À la place de `audience`, accepte un jeton émis pour l'une d'elles - le temps qu'une API renomme son audience. Aucune entrée vide ; exclusive de `audience`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.0.0"
              },
              "client": {
                "additionalProperties": false,
                "description": "The gateway's own client at this issuer: to exchange a caller's token for one issued to an upstream (RFC 8693), introspect opaque or delegated tokens, obtain a discovery token. Required as soon as an upstream declares `token_exchange` or `agents.delegation` is set.",
                "properties": {
                  "id": {
                    "description": "The gateway's client id at the issuer. Required.",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "The gateway's client id at the issuer. Required.",
                      "fr": "Identifiant du client de la passerelle chez l'émetteur. Obligatoire."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "0.7.0"
                  },
                  "secret": {
                    "description": "The client secret, by reference (`${VAR}` or `file:/path`), resolved at each use: a rotation is read without a reload. Never a value in clear.",
                    "pattern": "^(\\$\\{[A-Za-z_][A-Za-z0-9_]*\\}|file:/\\S+)$",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "The client secret, by reference (`${VAR}` or `file:/path`), resolved at each use: a rotation is read without a reload. Never a value in clear.",
                      "fr": "Secret du client, par référence (`${VAR}` ou `file:/chemin`), résolu à chaque usage : une rotation est lue sans rechargement. Jamais une valeur en clair."
                    },
                    "x-flexway-reference": true,
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "0.7.0"
                  }
                },
                "required": [
                  "id",
                  "secret"
                ],
                "type": "object",
                "x-flexway-description": {
                  "en": "The gateway's own client at this issuer: to exchange a caller's token for one issued to an upstream (RFC 8693), introspect opaque or delegated tokens, obtain a discovery token. Required as soon as an upstream declares `token_exchange` or `agents.delegation` is set.",
                  "fr": "Client de la passerelle chez cet émetteur : pour échanger un jeton d'appelant contre un jeton émis pour un amont (RFC 8693), introspecter des jetons opaques ou délégués, obtenir un jeton de découverte. Obligatoire dès qu'un amont déclare `token_exchange` ou que `agents.delegation` est présent."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.7.0"
              },
              "discovery": {
                "description": "URL of the provider's discovery document, ending with `/.well-known/openid-configuration`. An absolute `http(s)` URL; required. The issuer identifier is derived from it, unless `issuer` gives it.",
                "type": "string",
                "x-flexway-description": {
                  "en": "URL of the provider's discovery document, ending with `/.well-known/openid-configuration`. An absolute `http(s)` URL; required. The issuer identifier is derived from it, unless `issuer` gives it.",
                  "fr": "URL du document de découverte du fournisseur, terminée par `/.well-known/openid-configuration`. URL absolue `http(s)` ; obligatoire. L'identifiant de l'émetteur en est déduit, sauf si `issuer` le donne."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.3.0"
              },
              "issuer": {
                "description": "Identifier the provider states, when it differs from the discovery URL - a provider reached internally by one name and announcing its public one (split horizon). An absolute `http(s)` URL; the discovery document and every token must state exactly this value. Absent: derived from `discovery`.",
                "type": "string",
                "x-flexway-description": {
                  "en": "Identifier the provider states, when it differs from the discovery URL - a provider reached internally by one name and announcing its public one (split horizon). An absolute `http(s)` URL; the discovery document and every token must state exactly this value. Absent: derived from `discovery`.",
                  "fr": "Identifiant que le fournisseur énonce, quand il diffère de l'URL de découverte - un fournisseur joint en interne sous un nom et annonçant son nom public (horizon partagé). URL absolue `http(s)` ; le document de découverte et chaque jeton doivent énoncer exactement cette valeur. Absent : déduit de `discovery`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.9.0"
              },
              "name": {
                "description": "Name of the issuer in logs and metrics, unique. Required; `apikey` and `mtls` are reserved.",
                "type": "string",
                "x-flexway-description": {
                  "en": "Name of the issuer in logs and metrics, unique. Required; `apikey` and `mtls` are reserved.",
                  "fr": "Nom de l'émetteur dans les journaux et les métriques, unique. Obligatoire ; `apikey` et `mtls` sont réservés."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.3.0"
              },
              "opaque_tokens": {
                "additionalProperties": false,
                "description": "Makes this issuer the one that answers for tokens that are not JWTs: they are introspected (RFC 7662) with `client`, then required. At most one issuer: an opaque token names no issuer.",
                "properties": {
                  "cache": {
                    "default": "30s",
                    "description": "How long an introspection answer is reused - the delay before a revocation is seen -, never past the token's `exp`. A duration from `1s` to `5m`; default `30s`.",
                    "not": {
                      "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
                    },
                    "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "How long an introspection answer is reused - the delay before a revocation is seen -, never past the token's `exp`. A duration from `1s` to `5m`; default `30s`.",
                      "fr": "Durée de réutilisation d'une réponse d'introspection - le délai avant qu'une révocation soit vue -, jamais au-delà de l'`exp` du jeton. Durée de `1s` à `5m` ; défaut `30s`."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "1.0.0"
                  }
                },
                "type": "object",
                "x-flexway-description": {
                  "en": "Makes this issuer the one that answers for tokens that are not JWTs: they are introspected (RFC 7662) with `client`, then required. At most one issuer: an opaque token names no issuer.",
                  "fr": "Fait de cet émetteur celui qui répond des jetons qui ne sont pas des JWT : ils sont introspectés (RFC 7662) avec `client`, qui est alors obligatoire. Un seul émetteur au plus : un jeton opaque ne nomme aucun émetteur."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.0.0"
              },
              "roles_claim": {
                "description": "Dotted path of the claim holding the roles (`realm_access.roles` for Keycloak, `roles` for Entra ID). Absent: no role can be satisfied for this issuer.",
                "type": "string",
                "x-flexway-description": {
                  "en": "Dotted path of the claim holding the roles (`realm_access.roles` for Keycloak, `roles` for Entra ID). Absent: no role can be satisfied for this issuer.",
                  "fr": "Chemin pointé de la claim qui porte les rôles (`realm_access.roles` pour Keycloak, `roles` pour Entra ID). Absent : aucun rôle ne peut être satisfait pour cet émetteur."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.3.0"
              },
              "scopes_claim": {
                "default": "scope",
                "description": "Claim holding the scopes. Default `scope` (space-separated), then `scp`.",
                "type": "string",
                "x-flexway-description": {
                  "en": "Claim holding the scopes. Default `scope` (space-separated), then `scp`.",
                  "fr": "Claim qui porte les portées. Défaut `scope` (séparées par des espaces), puis `scp`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.3.0"
              },
              "service_accounts": {
                "additionalProperties": false,
                "description": "How this provider marks a token issued to a client acting for itself, when its subject is not the client id (Keycloak: `preferred_username` = `service-account-<client>`). `claim` and `prefix` are required.",
                "properties": {
                  "claim": {
                    "description": "Claim that marks a service account (for instance `preferred_username`). Required.",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "Claim that marks a service account (for instance `preferred_username`). Required.",
                      "fr": "Claim qui marque un compte de service (par exemple `preferred_username`). Obligatoire."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "1.0.0"
                  },
                  "prefix": {
                    "description": "Prefix of the `claim` value that marks a service account, followed by the client id (for instance `service-account-`). Required and non-empty: an empty prefix would mark every token.",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "Prefix of the `claim` value that marks a service account, followed by the client id (for instance `service-account-`). Required and non-empty: an empty prefix would mark every token.",
                      "fr": "Préfixe de la valeur de `claim` qui marque un compte de service, suivi de l'identifiant du client (par exemple `service-account-`). Obligatoire et non vide : un préfixe vide marquerait tous les jetons."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "1.0.0"
                  }
                },
                "required": [
                  "claim",
                  "prefix"
                ],
                "type": "object",
                "x-flexway-description": {
                  "en": "How this provider marks a token issued to a client acting for itself, when its subject is not the client id (Keycloak: `preferred_username` = `service-account-<client>`). `claim` and `prefix` are required.",
                  "fr": "Comment ce fournisseur marque un jeton émis à un client agissant pour lui-même, quand son sujet n'est pas l'identifiant du client (Keycloak : `preferred_username` = `service-account-<client>`). `claim` et `prefix` sont obligatoires."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.0.0"
              },
              "tenant_claim": {
                "description": "Name of the claim holding the tenant. Absent: requests from this issuer carry none.",
                "type": "string",
                "x-flexway-description": {
                  "en": "Name of the claim holding the tenant. Absent: requests from this issuer carry none.",
                  "fr": "Nom de la claim qui porte le tenant. Absente : les requêtes de cet émetteur n'en portent aucun."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.3.0"
              }
            },
            "required": [
              "discovery",
              "name"
            ],
            "type": "object"
          },
          "type": "array",
          "x-flexway-description": {
            "en": "Trusted token providers (OIDC), several at once: a customer usually has one for its employees and another for its end users. Two entries may not name the same issuer.",
            "fr": "Fournisseurs de jetons de confiance (OIDC), plusieurs à la fois : un client en a souvent un pour ses employés et un autre pour ses utilisateurs finaux. Deux entrées ne peuvent désigner le même émetteur."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.3.0"
        },
        "mtls": {
          "additionalProperties": false,
          "description": "Client certificates the gateway recognizes - an identity, required by a contract's `mutualTLS` scheme. Verified by the TLS listener (`server.tls`) or attested by a trusted edge's `x-forwarded-client-cert` header.",
          "properties": {
            "clients": {
              "description": "Recognized certificates, each bound to a tenant and to operations.",
              "items": {
                "additionalProperties": false,
                "properties": {
                  "id": {
                    "description": "Name of the certificate in logs and metrics, unique. Required.",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "Name of the certificate in logs and metrics, unique. Required.",
                      "fr": "Nom du certificat dans les journaux et les métriques, unique. Obligatoire."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "0.7.0"
                  },
                  "operations": {
                    "description": "Operation ids (`operationId`) this certificate opens - those only. Required and non-empty.",
                    "items": {
                      "type": "string"
                    },
                    "type": "array",
                    "x-flexway-description": {
                      "en": "Operation ids (`operationId`) this certificate opens - those only. Required and non-empty.",
                      "fr": "Identifiants d'opération (`operationId`) que ce certificat ouvre - et seulement eux. Obligatoire et non vide."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "0.7.0"
                  },
                  "subject": {
                    "description": "The certificate's Subject (for instance `CN=batch,O=Acme`). Exactly one of `uri` or `subject`.",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "The certificate's Subject (for instance `CN=batch,O=Acme`). Exactly one of `uri` or `subject`.",
                      "fr": "Sujet du certificat (par exemple `CN=batch,O=Acme`). Exactement un de `uri` ou `subject`."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "0.7.0"
                  },
                  "tenant": {
                    "description": "Tenant the certificate is bound to. Required.",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "Tenant the certificate is bound to. Required.",
                      "fr": "Tenant auquel le certificat est lié. Obligatoire."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "0.7.0"
                  },
                  "uri": {
                    "description": "The certificate's first URI SAN (a SPIFFE id, for instance `spiffe://bank.example/settler`). Exactly one of `uri` or `subject`.",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "The certificate's first URI SAN (a SPIFFE id, for instance `spiffe://bank.example/settler`). Exactly one of `uri` or `subject`.",
                      "fr": "Premier SAN URI du certificat (un identifiant SPIFFE par exemple, `spiffe://bank.example/settler`). Exactement un de `uri` ou `subject`."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "0.7.0"
                  }
                },
                "required": [
                  "id",
                  "tenant"
                ],
                "type": "object"
              },
              "type": "array",
              "x-flexway-description": {
                "en": "Recognized certificates, each bound to a tenant and to operations.",
                "fr": "Certificats reconnus, chacun lié à un tenant et à des opérations."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.7.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "Client certificates the gateway recognizes - an identity, required by a contract's `mutualTLS` scheme. Verified by the TLS listener (`server.tls`) or attested by a trusted edge's `x-forwarded-client-cert` header.",
            "fr": "Certificats clients reconnus par la passerelle - une identité, exigée par un schéma `mutualTLS` du contrat. Vérifiés par l'écouteur TLS (`server.tls`) ou attestés par l'en-tête `x-forwarded-client-cert` d'un edge de confiance."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.7.0"
        },
        "tenant_header": {
          "description": "Header the resolved tenant is written to, toward the upstream; whatever a caller sent under that name is overwritten. A header name (letters, digits, `-`). Empty: the tenant is not propagated (it is still a metric dimension).",
          "type": "string",
          "x-flexway-description": {
            "en": "Header the resolved tenant is written to, toward the upstream; whatever a caller sent under that name is overwritten. A header name (letters, digits, `-`). Empty: the tenant is not propagated (it is still a metric dimension).",
            "fr": "En-tête où le tenant résolu est écrit vers l'amont ; ce qu'un appelant a envoyé sous ce nom est écrasé. Nom d'en-tête (lettres, chiffres, `-`). Vide : le tenant n'est pas propagé (il reste une dimension des métriques)."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.3.0"
        },
        "trusted_headers": {
          "additionalProperties": false,
          "description": "Headers a trusted peer - a mesh ingress that authenticated the caller - writes the identity into. Believed from a peer of `server.trusted_proxies` only, then required; refused with `server.peer_identity_header`. The names are the deployment's.",
          "properties": {
            "subject": {
              "description": "Name of the header carrying the subject (the calling agent). Optional; a header name.",
              "type": "string",
              "x-flexway-description": {
                "en": "Name of the header carrying the subject (the calling agent). Optional; a header name.",
                "fr": "Nom de l'en-tête qui porte le sujet (l'agent appelant). Facultatif ; nom d'en-tête."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.8.0"
            },
            "tenant": {
              "description": "Name of the header carrying the tenant. Required; a header name (letters, digits, `-`).",
              "type": "string",
              "x-flexway-description": {
                "en": "Name of the header carrying the tenant. Required; a header name (letters, digits, `-`).",
                "fr": "Nom de l'en-tête qui porte le tenant. Obligatoire ; nom d'en-tête (lettres, chiffres, `-`)."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.8.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "Headers a trusted peer - a mesh ingress that authenticated the caller - writes the identity into. Believed from a peer of `server.trusted_proxies` only, then required; refused with `server.peer_identity_header`. The names are the deployment's.",
            "fr": "En-têtes où un pair de confiance - une entrée de maillage qui a authentifié l'appelant - écrit l'identité. Crus d'un pair de `server.trusted_proxies` seulement, qui est alors obligatoire ; refusés avec `server.peer_identity_header`. Les noms sont ceux du déploiement."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.8.0"
        }
      },
      "type": "object",
      "x-flexway-description": {
        "en": "How an identity is verified - never what an operation requires, which the contract declares (`security`): token issuers, API keys, client certificates, trusted headers.",
        "fr": "Comment une identité est vérifiée - jamais ce qu'une opération exige, que le contrat déclare (`security`) : émetteurs de jetons, clés d'API, certificats clients, en-têtes de confiance."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.3.0"
    },
    "contracts": {
      "additionalProperties": false,
      "description": "The files that carry the served set: the contract is the configuration. At least one contract is required (`openapi`, `protobuf`, `a2a` or `asyncapi`), except for a gateway that serves the inference surface (`ai`) alone. Paths are relative to the configuration file, read from disk at load, with no network access.",
      "properties": {
        "a2a": {
          "description": "Declared A2A agent cards (JSON files, `.json`): each method of an agent is an operation, served at the addresses its card declares and relayed to the upstream its `x-flexway-a2a` names. Each entry once, never empty.",
          "items": {
            "type": "string"
          },
          "type": "array",
          "x-flexway-description": {
            "en": "Declared A2A agent cards (JSON files, `.json`): each method of an agent is an operation, served at the addresses its card declares and relayed to the upstream its `x-flexway-a2a` names. Each entry once, never empty.",
            "fr": "Cartes d'agent A2A déclarées (fichiers JSON `.json`) : chaque méthode d'un agent est une opération, servie aux adresses de sa carte et relayée vers l'amont que nomme son `x-flexway-a2a`. Chaque entrée une seule fois, jamais vide."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        },
        "asyncapi": {
          "description": "AsyncAPI 3 document (`.yaml`, `.yml` or `.json`): its send and receive operations are the asynchronous plane - publications reached through OpenAPI operations marked `x-flexway-publish`, consumptions through `x-flexway-subscribe`, webhook deliveries declared with `x-flexway-deliver`.",
          "type": "string",
          "x-flexway-description": {
            "en": "AsyncAPI 3 document (`.yaml`, `.yml` or `.json`): its send and receive operations are the asynchronous plane - publications reached through OpenAPI operations marked `x-flexway-publish`, consumptions through `x-flexway-subscribe`, webhook deliveries declared with `x-flexway-deliver`.",
            "fr": "Document AsyncAPI 3 (`.yaml`, `.yml` ou `.json`) : ses opérations `send` et `receive` forment le plan asynchrone - publications atteintes par les opérations OpenAPI marquées `x-flexway-publish`, consommations par `x-flexway-subscribe`, livraisons webhook déclarées par `x-flexway-deliver`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.5.0"
        },
        "openapi": {
          "description": "Default OpenAPI contract: served on every host that declares no `contracts` of its own, and on any host not declared at all. Optional once some host declares its own.",
          "type": "string",
          "x-flexway-description": {
            "en": "Default OpenAPI contract: served on every host that declares no `contracts` of its own, and on any host not declared at all. Optional once some host declares its own.",
            "fr": "Contrat OpenAPI par défaut : servi sur chaque hôte qui ne déclare pas ses propres `contracts`, et sur tout hôte non déclaré. Facultatif dès qu'un hôte déclare les siens."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.1.0"
        },
        "protobuf": {
          "description": "Protobuf descriptor sets (`FileDescriptorSet`, imports included - `buf build`, or `protoc` with its imports), with extension `.binpb`, `.pb` or `.protoset`, served beside the OpenAPI on the same hosts: every method of every service they declare is an operation.",
          "items": {
            "type": "string"
          },
          "type": "array",
          "x-flexway-description": {
            "en": "Protobuf descriptor sets (`FileDescriptorSet`, imports included - `buf build`, or `protoc` with its imports), with extension `.binpb`, `.pb` or `.protoset`, served beside the OpenAPI on the same hosts: every method of every service they declare is an operation.",
            "fr": "Jeux de descripteurs Protobuf (`FileDescriptorSet`, imports compris - `buf build` ou `protoc` avec ses imports), extensions `.binpb`, `.pb` ou `.protoset`, servis à côté de l'OpenAPI sur les mêmes hôtes : chaque méthode de chaque service déclaré est une opération."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.1.0"
        }
      },
      "type": "object",
      "x-flexway-description": {
        "en": "The files that carry the served set: the contract is the configuration. At least one contract is required (`openapi`, `protobuf`, `a2a` or `asyncapi`), except for a gateway that serves the inference surface (`ai`) alone. Paths are relative to the configuration file, read from disk at load, with no network access.",
        "fr": "Les fichiers qui portent l'ensemble servi : le contrat est la configuration. Au moins un des contrats est requis (`openapi`, `protobuf`, `a2a` ou `asyncapi`), sauf pour une passerelle qui ne sert que la surface d'inférence (`ai`). Chemins relatifs au fichier de configuration, lus sur disque au chargement, sans accès réseau."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.1.0"
    },
    "errors": {
      "additionalProperties": false,
      "description": "Shape of the RFC 9457 problem documents of the product routes. The inference surface `/v1/*` keeps the OpenAI envelope.",
      "properties": {
        "field_codes": {
          "additionalProperties": {
            "type": "string"
          },
          "description": "Renames the code of a field error (`errors[].code` of a 422 answer): a JSON Schema keyword a request can break (`required`, `type`, `enum`, `pattern`, `minLength`...) or `invalid`, to the operator's own token (letters, digits, `_ . -`, 64 at most). A keyword not listed keeps its name.",
          "propertyNames": {
            "enum": [
              "additionalProperties",
              "allOf",
              "anyOf",
              "const",
              "contains",
              "dependentRequired",
              "else",
              "enum",
              "exclusiveMaximum",
              "exclusiveMinimum",
              "format",
              "if",
              "invalid",
              "maxContains",
              "maxItems",
              "maxLength",
              "maxProperties",
              "maximum",
              "minContains",
              "minItems",
              "minLength",
              "minProperties",
              "minimum",
              "multipleOf",
              "not",
              "oneOf",
              "pattern",
              "propertyNames",
              "required",
              "then",
              "type",
              "unevaluatedItems",
              "unevaluatedProperties",
              "uniqueItems"
            ]
          },
          "type": "object",
          "x-flexway-description": {
            "en": "Renames the code of a field error (`errors[].code` of a 422 answer): a JSON Schema keyword a request can break (`required`, `type`, `enum`, `pattern`, `minLength`...) or `invalid`, to the operator's own token (letters, digits, `_ . -`, 64 at most). A keyword not listed keeps its name.",
            "fr": "Renomme le code d'une erreur de champ (`errors[].code` d'une réponse 422) : un mot-clé JSON Schema qu'une requête peut enfreindre (`required`, `type`, `enum`, `pattern`, `minLength`...) ou `invalid`, vers un jeton du client (lettres, chiffres, `_ . -`, 64 au plus). Un mot-clé non listé garde son nom."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.0.0"
        },
        "type_base": {
          "description": "Namespace of the problems' `type`: an absolute http(s) URL ending with `/`, to which the code is appended - the operator's portal rather than the product's. Absent: the product's default namespace.",
          "type": "string",
          "x-flexway-description": {
            "en": "Namespace of the problems' `type`: an absolute http(s) URL ending with `/`, to which the code is appended - the operator's portal rather than the product's. Absent: the product's default namespace.",
            "fr": "Espace de noms du champ `type` des erreurs : une URL http(s) absolue terminée par `/`, à laquelle le code est ajouté - le portail du client plutôt que celui du produit. Absent : l'espace de noms par défaut du produit."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.0.0"
        }
      },
      "type": "object",
      "x-flexway-description": {
        "en": "Shape of the RFC 9457 problem documents of the product routes. The inference surface `/v1/*` keeps the OpenAI envelope.",
        "fr": "Forme des documents d'erreur RFC 9457 des routes produit. La surface d'inférence `/v1/*` garde l'enveloppe OpenAI."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.0.0"
    },
    "hosts": {
      "additionalProperties": {
        "additionalProperties": false,
        "properties": {
          "contracts": {
            "description": "OpenAPI contracts this host serves - exactly their union, nothing of the default contract. Paths relative to the configuration file, each listed once. Absent: the default contract (`contracts.openapi`).",
            "items": {
              "type": "string"
            },
            "type": "array",
            "x-flexway-description": {
              "en": "OpenAPI contracts this host serves - exactly their union, nothing of the default contract. Paths relative to the configuration file, each listed once. Absent: the default contract (`contracts.openapi`).",
              "fr": "Contrats OpenAPI que sert cet hôte - exactement leur union, rien du contrat par défaut. Chemins relatifs au fichier de configuration, chacun une seule fois. Absent : le contrat par défaut (`contracts.openapi`)."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "0.6.0"
          },
          "default_upstream": {
            "description": "Upstream (a name declared in `upstreams`) of this host's operations that name none with `x-flexway-upstream`.",
            "type": "string",
            "x-flexway-description": {
              "en": "Upstream (a name declared in `upstreams`) of this host's operations that name none with `x-flexway-upstream`.",
              "fr": "Amont (nom déclaré dans `upstreams`) des opérations de cet hôte qui n'en nomment pas par `x-flexway-upstream`."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "0.1.0"
          },
          "validation": {
            "default": "full",
            "description": "How much of a request is validated against the contract on this host: `full` (default, everything), `params` (parameters only, the body is relayed unread and the service validates it) or `off`. An operation's own `x-flexway-validation` overrides it.",
            "enum": [
              "full",
              "params",
              "off"
            ],
            "type": "string",
            "x-flexway-description": {
              "en": "How much of a request is validated against the contract on this host: `full` (default, everything), `params` (parameters only, the body is relayed unread and the service validates it) or `off`. An operation's own `x-flexway-validation` overrides it.",
              "fr": "Part d'une requête validée contre le contrat sur cet hôte : `full` (défaut, tout), `params` (paramètres seulement, le corps est relayé sans être lu et le service le valide) ou `off`. Le `x-flexway-validation` d'une opération l'emporte."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "1.0.0"
          }
        },
        "type": "object"
      },
      "description": "The hosts served, by name (the request's authority): each groups the operations served under that name and gives them a default upstream.",
      "type": "object",
      "x-flexway-description": {
        "en": "The hosts served, by name (the request's authority): each groups the operations served under that name and gives them a default upstream.",
        "fr": "Les hôtes servis, par nom (l'autorité de la requête) : chacun regroupe les opérations servies sous ce nom et leur donne un amont par défaut."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.1.0"
    },
    "kms": {
      "additionalProperties": false,
      "description": "The key management service of field-level encryption on the Kafka listener: it wraps the data keys the gateway draws, under a key that never leaves it. Exactly one kind is written: `vault_transit`, `aws_kms`, `gcp_kms` or `local`; absent, a contract that declares `x-flexway-encrypt` is refused at load.",
      "properties": {
        "aws_kms": {
          "additionalProperties": false,
          "description": "AWS KMS. Without `credentials_file`, credentials come from the SDK's default chain (IRSA, instance role).",
          "properties": {
            "credentials_file": {
              "description": "Path of a mounted AWS shared credentials file (never a value); the file must exist. Absent: the SDK's default chain.",
              "pattern": "^(\\$\\{[A-Za-z_][A-Za-z0-9_]*\\}|file:/\\S+)$",
              "type": "string",
              "x-flexway-description": {
                "en": "Path of a mounted AWS shared credentials file (never a value); the file must exist. Absent: the SDK's default chain.",
                "fr": "Chemin d'un fichier d'identifiants partagés AWS monté (pas une valeur) ; le fichier doit exister. Absent : chaîne par défaut du SDK."
              },
              "x-flexway-reference": true,
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "endpoint": {
              "description": "An `https://` URL of a KMS endpoint other than the region's (private endpoint, emulator). Absent: the region's public endpoint.",
              "type": "string",
              "x-flexway-description": {
                "en": "An `https://` URL of a KMS endpoint other than the region's (private endpoint, emulator). Absent: the region's public endpoint.",
                "fr": "Adresse `https://` d'un point d'accès KMS autre que celui de la région (point d'accès privé, émulateur). Absent : le point d'accès public de la région."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "profile": {
              "description": "The profile to read in `credentials_file`; refused when `credentials_file` is not written.",
              "type": "string",
              "x-flexway-description": {
                "en": "The profile to read in `credentials_file`; refused when `credentials_file` is not written.",
                "fr": "Profil à lire dans `credentials_file` ; refusé si `credentials_file` n'est pas écrit."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "region": {
              "description": "The AWS region of the key (`eu-west-3`); required.",
              "type": "string",
              "x-flexway-description": {
                "en": "The AWS region of the key (`eu-west-3`); required.",
                "fr": "Région AWS de la clé (`eu-west-3`) ; obligatoire."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            }
          },
          "required": [
            "region"
          ],
          "type": "object",
          "x-flexway-description": {
            "en": "AWS KMS. Without `credentials_file`, credentials come from the SDK's default chain (IRSA, instance role).",
            "fr": "AWS KMS. Sans `credentials_file`, les identifiants viennent de la chaîne par défaut du SDK (IRSA, rôle d'instance)."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        },
        "cache": {
          "additionalProperties": false,
          "description": "Bounds the data keys kept unwrapped in memory: by number, by time, and how long a KMS refusal is remembered.",
          "properties": {
            "max_keys": {
              "default": 10000,
              "description": "Number of data keys kept unwrapped, shared between tenants; from 1 to 1,000,000, default `10000`.",
              "maximum": 1000000,
              "minimum": 1,
              "type": "integer",
              "x-flexway-description": {
                "en": "Number of data keys kept unwrapped, shared between tenants; from 1 to 1,000,000, default `10000`.",
                "fr": "Nombre de clés de données gardées déchiffrées, partagé entre tenants ; de 1 à 1 000 000, défaut `10000`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "negative_ttl": {
              "default": "5s",
              "description": "How long a KMS refusal is remembered before asking again; from `100ms` to `5m`, default `5s`. A key erasure takes effect within `ttl` + `negative_ttl`.",
              "not": {
                "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
              },
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "How long a KMS refusal is remembered before asking again; from `100ms` to `5m`, default `5s`. A key erasure takes effect within `ttl` + `negative_ttl`.",
                "fr": "Durée pendant laquelle un refus du KMS est retenu avant de redemander ; de `100ms` à `5m`, défaut `5s`. Un effacement de clé prend effet au plus après `ttl` + `negative_ttl`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "ttl": {
              "default": "1h",
              "description": "Lifetime of an unwrapped data key in memory, counted from its unwrapping; the writing key is checked again with the KMS every `ttl`. From `1s` to `24h`, default `1h`.",
              "not": {
                "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
              },
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "Lifetime of an unwrapped data key in memory, counted from its unwrapping; the writing key is checked again with the KMS every `ttl`. From `1s` to `24h`, default `1h`.",
                "fr": "Durée de vie d'une clé de données déchiffrée en mémoire, comptée depuis son déchiffrement ; la clé d'écriture est revérifiée au KMS à chaque `ttl`. De `1s` à `24h`, défaut `1h`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "Bounds the data keys kept unwrapped in memory: by number, by time, and how long a KMS refusal is remembered.",
            "fr": "Borne les clés de données gardées déchiffrées en mémoire : en nombre, en durée, et la mémoire d'un refus du KMS."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        },
        "gcp_kms": {
          "additionalProperties": false,
          "description": "Google Cloud KMS. Without `credentials_file`, Application Default Credentials (Workload Identity).",
          "properties": {
            "credentials_file": {
              "description": "Path of a mounted service account key (never a value); the file must exist. Absent: Application Default Credentials.",
              "pattern": "^(\\$\\{[A-Za-z_][A-Za-z0-9_]*\\}|file:/\\S+)$",
              "type": "string",
              "x-flexway-description": {
                "en": "Path of a mounted service account key (never a value); the file must exist. Absent: Application Default Credentials.",
                "fr": "Chemin d'une clé de compte de service monté (pas une valeur) ; le fichier doit exister. Absent : identifiants par défaut de l'application."
              },
              "x-flexway-reference": true,
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "endpoint": {
              "description": "A Cloud KMS endpoint other than the public one; absent: `cloudkms.googleapis.com`.",
              "type": "string",
              "x-flexway-description": {
                "en": "A Cloud KMS endpoint other than the public one; absent: `cloudkms.googleapis.com`.",
                "fr": "Point d'accès de Cloud KMS autre que le public ; absent : `cloudkms.googleapis.com`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "Google Cloud KMS. Without `credentials_file`, Application Default Credentials (Workload Identity).",
            "fr": "Google Cloud KMS. Sans `credentials_file`, les identifiants par défaut de l'application (Workload Identity)."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        },
        "key": {
          "description": "The KMS key that wraps the data keys: a Vault transit key, an AWS key id, ARN or alias, a resource name `projects/<p>/locations/<l>/keyRings/<r>/cryptoKeys/<k>` for GCP, a key file for `local`. `{tenant}` makes it one key per tenant (destroying it erases that tenant's fields alone). Letters, digits and `. _ : / @ + = , -`; a Vault or local key is a single name, without `/` or `:`. Required, checked at start.",
          "type": "string",
          "x-flexway-description": {
            "en": "The KMS key that wraps the data keys: a Vault transit key, an AWS key id, ARN or alias, a resource name `projects/<p>/locations/<l>/keyRings/<r>/cryptoKeys/<k>` for GCP, a key file for `local`. `{tenant}` makes it one key per tenant (destroying it erases that tenant's fields alone). Letters, digits and `. _ : / @ + = , -`; a Vault or local key is a single name, without `/` or `:`. Required, checked at start.",
            "fr": "La clé du KMS qui enveloppe les clés de données : clé transit Vault, identifiant, ARN ou alias AWS, nom de ressource `projects/<p>/locations/<l>/keyRings/<r>/cryptoKeys/<k>` pour GCP, fichier de clé en `local`. `{tenant}` en fait une clé par tenant (détruire la clé efface les champs de ce seul tenant). Lettres, chiffres et `. _ : / @ + = , -` ; une clé Vault ou locale est un seul nom, sans `/` ni `:`. Obligatoire, vérifiée au démarrage."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        },
        "local": {
          "additionalProperties": false,
          "description": "Keys in files of a mounted directory: tests and development only.",
          "properties": {
            "dir": {
              "description": "Directory of the key files; required, it must exist.",
              "type": "string",
              "x-flexway-description": {
                "en": "Directory of the key files; required, it must exist.",
                "fr": "Répertoire des fichiers de clés ; obligatoire, il doit exister."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            }
          },
          "required": [
            "dir"
          ],
          "type": "object",
          "x-flexway-description": {
            "en": "Keys in files of a mounted directory: tests and development only.",
            "fr": "Clés dans des fichiers d'un répertoire monté : tests et développement seulement."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        },
        "previous_keys": {
          "description": "Former values of `key` a record may still name: read, never written; a record naming any other key is refused. Same syntax as `key`, `{tenant}` included; 8 at most, no duplicate nor `key` itself.",
          "items": {
            "type": "string"
          },
          "maxItems": 8,
          "type": "array",
          "x-flexway-description": {
            "en": "Former values of `key` a record may still name: read, never written; a record naming any other key is refused. Same syntax as `key`, `{tenant}` included; 8 at most, no duplicate nor `key` itself.",
            "fr": "Anciennes valeurs de `key` qu'un enregistrement peut encore nommer : lues, jamais écrites ; un enregistrement qui nomme une autre clé est refusé. Même syntaxe que `key`, `{tenant}` compris ; 8 au plus, sans doublon ni `key` elle-même."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        },
        "rotation": {
          "additionalProperties": false,
          "description": "When a new data key starts: after `interval` or `max_encryptions` encrypted fields, whichever comes first.",
          "properties": {
            "interval": {
              "default": "1h",
              "description": "How long a data key is used before the next one; from `1m` to `168h` (7 days), default `1h`.",
              "not": {
                "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
              },
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "How long a data key is used before the next one; from `1m` to `168h` (7 days), default `1h`.",
                "fr": "Durée d'usage d'une clé de données avant la suivante ; de `1m` à `168h` (7 jours), défaut `1h`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "max_encryptions": {
              "default": 5000000,
              "description": "Number of fields encrypted under one data key before the next; from 1 to 2^30 (1,073,741,824), default `5000000`.",
              "maximum": 1073741824,
              "minimum": 1,
              "type": "integer",
              "x-flexway-description": {
                "en": "Number of fields encrypted under one data key before the next; from 1 to 2^30 (1,073,741,824), default `5000000`.",
                "fr": "Nombre de champs chiffrés sous une même clé de données avant la suivante ; de 1 à 2^30 (1 073 741 824), défaut `5000000`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "When a new data key starts: after `interval` or `max_encryptions` encrypted fields, whichever comes first.",
            "fr": "Quand une nouvelle clé de données commence : après `interval` ou `max_encryptions` champs chiffrés, au premier atteint."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        },
        "tenant_calls": {
          "additionalProperties": false,
          "description": "Token bucket of the KMS calls one tenant's records cause: a producer that exhausts its own never touches another tenant's.",
          "properties": {
            "burst": {
              "default": 20,
              "description": "KMS calls allowed at once for one tenant; at least 1, default `20`.",
              "minimum": 1,
              "type": "integer",
              "x-flexway-description": {
                "en": "KMS calls allowed at once for one tenant; at least 1, default `20`.",
                "fr": "Appels au KMS permis d'un coup pour un tenant ; au moins 1, défaut `20`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "rate": {
              "default": 10,
              "description": "KMS calls per second for one tenant; more than 0, default `10`.",
              "type": "number",
              "x-flexway-description": {
                "en": "KMS calls per second for one tenant; more than 0, default `10`.",
                "fr": "Appels au KMS par seconde pour un tenant ; plus de 0, défaut `10`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "Token bucket of the KMS calls one tenant's records cause: a producer that exhausts its own never touches another tenant's.",
            "fr": "Seau à jetons des appels au KMS que causent les enregistrements d'un tenant : un producteur qui épuise le sien n'entame jamais celui d'un autre tenant."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        },
        "timeout": {
          "default": "2s",
          "description": "Timeout of one KMS call, which holds the Kafka request that needs it; more than 0 and `30s` at most, default `2s`. KMS unavailable: `KAFKA_STORAGE_ERROR`, never cleartext.",
          "not": {
            "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
          },
          "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
          "type": "string",
          "x-flexway-description": {
            "en": "Timeout of one KMS call, which holds the Kafka request that needs it; more than 0 and `30s` at most, default `2s`. KMS unavailable: `KAFKA_STORAGE_ERROR`, never cleartext.",
            "fr": "Délai d'un appel au KMS, qui retient la requête Kafka qui en a besoin ; plus de 0 et `30s` au plus, défaut `2s`. KMS indisponible : `KAFKA_STORAGE_ERROR`, jamais un clair."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        },
        "vault_transit": {
          "additionalProperties": false,
          "description": "Vault's transit engine, with a derived key (its context binds tenant and topic). Authentication by `token` or by `kubernetes`, exactly one.",
          "properties": {
            "address": {
              "description": "Vault's absolute `https://` URL (`https://vault.security:8200`), without credentials nor query; `http://` is refused: the token would travel in clear. Required.",
              "type": "string",
              "x-flexway-description": {
                "en": "Vault's absolute `https://` URL (`https://vault.security:8200`), without credentials nor query; `http://` is refused: the token would travel in clear. Required.",
                "fr": "Adresse absolue de Vault en `https://` (`https://vault.security:8200`), sans identifiants ni paramètres ; `http://` est refusé : le jeton circulerait en clair. Obligatoire."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "kubernetes": {
              "additionalProperties": false,
              "description": "Vault's Kubernetes auth method: the pod's service account token, for a role. Exclusive with `token`.",
              "properties": {
                "mount": {
                  "default": "kubernetes",
                  "description": "Path of the Kubernetes auth method in Vault; default `kubernetes`.",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "Path of the Kubernetes auth method in Vault; default `kubernetes`.",
                    "fr": "Chemin de la méthode d'authentification Kubernetes dans Vault ; défaut `kubernetes`."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "role": {
                  "description": "The Vault role requested with the service account token; required.",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "The Vault role requested with the service account token; required.",
                    "fr": "Rôle Vault demandé avec le jeton du compte de service ; obligatoire."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "token_file": {
                  "default": "/var/run/secrets/kubernetes.io/serviceaccount/token",
                  "description": "File of the service account token; default `/var/run/secrets/kubernetes.io/serviceaccount/token`.",
                  "pattern": "^(\\$\\{[A-Za-z_][A-Za-z0-9_]*\\}|file:/\\S+)$",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "File of the service account token; default `/var/run/secrets/kubernetes.io/serviceaccount/token`.",
                    "fr": "Fichier du jeton du compte de service ; défaut `/var/run/secrets/kubernetes.io/serviceaccount/token`."
                  },
                  "x-flexway-reference": true,
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                }
              },
              "required": [
                "role"
              ],
              "type": "object",
              "x-flexway-description": {
                "en": "Vault's Kubernetes auth method: the pod's service account token, for a role. Exclusive with `token`.",
                "fr": "Méthode d'authentification Kubernetes de Vault : le jeton du compte de service du pod, pour un rôle. Exclusive de `token`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "mount": {
              "default": "transit",
              "description": "Path of the transit engine in Vault; segments of letters, digits, `.`, `_`, `-` separated by `/`. Default `transit`.",
              "type": "string",
              "x-flexway-description": {
                "en": "Path of the transit engine in Vault; segments of letters, digits, `.`, `_`, `-` separated by `/`. Default `transit`.",
                "fr": "Chemin du moteur transit dans Vault ; segments de lettres, chiffres, `.`, `_`, `-` séparés par `/`. Défaut `transit`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "namespace": {
              "description": "Vault namespace (Vault Enterprise); optional.",
              "type": "string",
              "x-flexway-description": {
                "en": "Vault namespace (Vault Enterprise); optional.",
                "fr": "Espace de noms Vault (Vault Enterprise) ; facultatif."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "tls": {
              "additionalProperties": false,
              "description": "Client TLS toward Vault: trusted authority, client certificate, expected name.",
              "properties": {
                "ca_file": {
                  "description": "PEM file of the authority that verifies the server's certificate; absent: the system's authorities. The file must exist.",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "PEM file of the authority that verifies the server's certificate; absent: the system's authorities. The file must exist.",
                    "fr": "Fichier PEM de l'autorité qui vérifie le certificat du serveur ; absent : les autorités du système. Le fichier doit exister."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "cert_file": {
                  "description": "Client certificate (PEM) presented to Vault; goes with `key_file`. The file must exist.",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "Client certificate (PEM) presented to Vault; goes with `key_file`. The file must exist.",
                    "fr": "Certificat client PEM présenté à Vault ; va avec `key_file`. Le fichier doit exister."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "key_file": {
                  "description": "Private key (PEM) of the client certificate; goes with `cert_file`. The file must exist.",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "Private key (PEM) of the client certificate; goes with `cert_file`. The file must exist.",
                    "fr": "Clé privée PEM du certificat client ; va avec `cert_file`. Le fichier doit exister."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "server_name": {
                  "description": "Name expected in Vault's certificate, when it differs from the host of `address`.",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "Name expected in Vault's certificate, when it differs from the host of `address`.",
                    "fr": "Nom attendu dans le certificat de Vault, quand il diffère de l'hôte de `address`."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                }
              },
              "type": "object",
              "x-flexway-description": {
                "en": "Client TLS toward Vault: trusted authority, client certificate, expected name.",
                "fr": "TLS client vers Vault : autorité de confiance, certificat client, nom attendu."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "token": {
              "description": "Vault token by reference, `${VAR}` or `file:/path`, read at each call; never the value. Exclusive with `kubernetes`.",
              "pattern": "^(\\$\\{[A-Za-z_][A-Za-z0-9_]*\\}|file:/\\S+)$",
              "type": "string",
              "x-flexway-description": {
                "en": "Vault token by reference, `${VAR}` or `file:/path`, read at each call; never the value. Exclusive with `kubernetes`.",
                "fr": "Jeton Vault par référence, `${VAR}` ou `file:/chemin`, relu à chaque appel ; jamais la valeur. Exclusif de `kubernetes`."
              },
              "x-flexway-reference": true,
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            }
          },
          "required": [
            "address"
          ],
          "type": "object",
          "x-flexway-description": {
            "en": "Vault's transit engine, with a derived key (its context binds tenant and topic). Authentication by `token` or by `kubernetes`, exactly one.",
            "fr": "Le moteur transit de Vault, clé dérivée (son contexte lie le tenant et le sujet). Authentification par `token` ou par `kubernetes`, l'une des deux."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        }
      },
      "required": [
        "key"
      ],
      "type": "object",
      "x-flexway-description": {
        "en": "The key management service of field-level encryption on the Kafka listener: it wraps the data keys the gateway draws, under a key that never leaves it. Exactly one kind is written: `vault_transit`, `aws_kms`, `gcp_kms` or `local`; absent, a contract that declares `x-flexway-encrypt` is refused at load.",
        "fr": "Le service de gestion de clés du chiffrement par champ sur l'écouteur Kafka : il enveloppe les clés de données que la passerelle tire, sous une clé qui ne le quitte jamais. Exactement un genre est écrit : `vault_transit`, `aws_kms`, `gcp_kms` ou `local` ; absent, un contrat qui déclare `x-flexway-encrypt` est refusé au chargement."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.6.0"
    },
    "listeners": {
      "additionalProperties": false,
      "description": "The gateway's entry points beside HTTP.",
      "properties": {
        "kafka": {
          "additionalProperties": false,
          "description": "The Kafka listener: Kafka producers, consumers and admin tools reach the virtual clusters the AsyncAPI contract declares (`x-flexway-kafka-proxy`), under the same decision as HTTP. Nothing here lists a topic: the contract does. One TLS port, the broker named by the client's SNI (`address`), or plaintext ports inside a mesh (`plaintext`); requires `contracts.asyncapi`.",
          "properties": {
            "address": {
              "description": "The TLS listener's `host:port` address (`:9093`); requires `tls` and `sni_domain`. Absent: plaintext ports only. Read once at start.",
              "type": "string",
              "x-flexway-description": {
                "en": "The TLS listener's `host:port` address (`:9093`); requires `tls` and `sni_domain`. Absent: plaintext ports only. Read once at start.",
                "fr": "Adresse `hôte:port` de l'écouteur TLS (`:9093`) ; exige `tls` et `sni_domain`. Absente : ports en clair seulement. Lue une fois au démarrage."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "1.6.0"
            },
            "advertised_port": {
              "description": "Port written into the broker addresses a client is given (Metadata, FindCoordinator): the one a load balancer exposes. From 1 to 65535; absent: the port of `address`. Only with `address`.",
              "maximum": 65535,
              "minimum": 1,
              "type": "integer",
              "x-flexway-description": {
                "en": "Port written into the broker addresses a client is given (Metadata, FindCoordinator): the one a load balancer exposes. From 1 to 65535; absent: the port of `address`. Only with `address`.",
                "fr": "Port écrit dans les adresses de courtier données au client (Metadata, FindCoordinator) : celui qu'expose un répartiteur de charge. De 1 à 65535 ; absent : le port d'`address`. Seulement avec `address`."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "1.6.0"
            },
            "auth_timeout": {
              "default": "10s",
              "description": "Absolute time a connection has to authenticate; more than 0 and `1m` at most, default `10s`.",
              "not": {
                "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
              },
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "Absolute time a connection has to authenticate; more than 0 and `1m` at most, default `10s`.",
                "fr": "Délai absolu dont dispose une connexion pour s'authentifier ; plus de 0 et `1m` au plus, défaut `10s`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "idle_timeout": {
              "default": "10m",
              "description": "Closes a connection that sent nothing for this long (Kafka's `connections.max.idle.ms`); at least `1s`, default `10m`.",
              "not": {
                "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
              },
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "Closes a connection that sent nothing for this long (Kafka's `connections.max.idle.ms`); at least `1s`, default `10m`.",
                "fr": "Ferme une connexion qui n'a rien envoyé pendant cette durée (`connections.max.idle.ms` de Kafka) ; `1s` au moins, défaut `10m`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "max_connection_rate_per_tenant": {
              "default": 100,
              "description": "Connections one tenant opens per second, counted at authentication (a one-second bucket): a client reconnecting in a loop costs its own tenant's places, never the others'. From 0 (no bound) to 100000, default `100`.",
              "maximum": 100000,
              "minimum": 0,
              "type": "number",
              "x-flexway-description": {
                "en": "Connections one tenant opens per second, counted at authentication (a one-second bucket): a client reconnecting in a loop costs its own tenant's places, never the others'. From 0 (no bound) to 100000, default `100`.",
                "fr": "Connexions qu'un tenant ouvre par seconde, comptées à l'authentification (seau d'une seconde) : un client qui se reconnecte en boucle coûte les places de son tenant, jamais celles des autres. De 0 (sans borne) à 100000, défaut `100`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "max_connections": {
              "default": 4096,
              "description": "Client connections open at once; past it, a new one waits to be accepted. From 1 to 100000, default `4096`.",
              "maximum": 100000,
              "minimum": 1,
              "type": "integer",
              "x-flexway-description": {
                "en": "Client connections open at once; past it, a new one waits to be accepted. From 1 to 100000, default `4096`.",
                "fr": "Connexions clientes ouvertes à la fois ; au-delà, une nouvelle attend d'être acceptée. De 1 à 100000, défaut `4096`."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "1.6.0"
            },
            "max_connections_per_ip": {
              "default": 16,
              "description": "Connections of one client address; from 0 (no bound, behind a proxy that hides the addresses) to `max_connections`, default `16`.",
              "minimum": 0,
              "type": "integer",
              "x-flexway-description": {
                "en": "Connections of one client address; from 0 (no bound, behind a proxy that hides the addresses) to `max_connections`, default `16`.",
                "fr": "Connexions d'une même adresse cliente ; de 0 (sans borne, derrière un proxy qui masque les adresses) à `max_connections`, défaut `16`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "max_connections_per_tenant": {
              "default": 1024,
              "description": "Connections of one tenant, counted at authentication; from 1 to `max_connections`, default `1024`.",
              "minimum": 1,
              "type": "integer",
              "x-flexway-description": {
                "en": "Connections of one tenant, counted at authentication; from 1 to `max_connections`, default `1024`.",
                "fr": "Connexions d'un même tenant, comptées à l'authentification ; de 1 à `max_connections`, défaut `1024`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "max_fetch_wait": {
              "default": "30s",
              "description": "Longest a `Fetch` may wait at the broker for data (its `max_wait_ms`); from `100ms` to `5m`, default `30s`.",
              "not": {
                "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
              },
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "Longest a `Fetch` may wait at the broker for data (its `max_wait_ms`); from `100ms` to `5m`, default `30s`.",
                "fr": "Attente maximale d'un `Fetch` chez le courtier pour des données (son `max_wait_ms`) ; de `100ms` à `5m`, défaut `30s`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "max_in_flight_bytes": {
              "anyOf": [
                {
                  "minimum": 1,
                  "type": "integer"
                },
                {
                  "pattern": "^\\s*[1-9][0-9]*\\s*(B|KiB|MiB|GiB)?\\s*$",
                  "type": "string"
                }
              ],
              "default": "64MiB",
              "description": "Answers one connection holds in memory, read from the broker and not yet written; past it, the listener stops reading the broker (backpressure, never a refusal). A size (`64MiB`) from `1MiB` to `max_total_in_flight_bytes`, default `64MiB`.",
              "x-flexway-description": {
                "en": "Answers one connection holds in memory, read from the broker and not yet written; past it, the listener stops reading the broker (backpressure, never a refusal). A size (`64MiB`) from `1MiB` to `max_total_in_flight_bytes`, default `64MiB`.",
                "fr": "Réponses qu'une connexion garde en mémoire, lues du courtier et pas encore écrites ; au-delà, l'écouteur cesse de lire le courtier (contre-pression, jamais un refus). Taille (`64MiB`) de `1MiB` à `max_total_in_flight_bytes`, défaut `64MiB`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "max_request_bytes": {
              "anyOf": [
                {
                  "minimum": 1,
                  "type": "integer"
                },
                {
                  "pattern": "^\\s*[1-9][0-9]*\\s*(B|KiB|MiB|GiB)?\\s*$",
                  "type": "string"
                }
              ],
              "default": "16MiB",
              "description": "Largest request frame of an authenticated client, read whole before it is decoded; from `64KiB` to `100MiB`, default `16MiB`. Before authentication, 64 KiB only.",
              "x-flexway-description": {
                "en": "Largest request frame of an authenticated client, read whole before it is decoded; from `64KiB` to `100MiB`, default `16MiB`. Before authentication, 64 KiB only.",
                "fr": "Taille maximale d'une trame de requête d'un client authentifié, lue en entier avant d'être décodée ; de `64KiB` à `100MiB`, défaut `16MiB`. Avant l'authentification, 64 Kio seulement."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "max_response_bytes": {
              "anyOf": [
                {
                  "minimum": 1,
                  "type": "integer"
                },
                {
                  "pattern": "^\\s*[1-9][0-9]*\\s*(B|KiB|MiB|GiB)?\\s*$",
                  "type": "string"
                }
              ],
              "default": "64MiB",
              "description": "Largest broker response; a `Fetch`'s `MaxBytes` is held below half of it. From `1MiB` to `256MiB`, default `64MiB`; with encrypted fields, at least `max_request_bytes`.",
              "x-flexway-description": {
                "en": "Largest broker response; a `Fetch`'s `MaxBytes` is held below half of it. From `1MiB` to `256MiB`, default `64MiB`; with encrypted fields, at least `max_request_bytes`.",
                "fr": "Taille maximale d'une réponse du courtier ; le `MaxBytes` d'un `Fetch` est tenu sous sa moitié. De `1MiB` à `256MiB`, défaut `64MiB` ; avec des champs chiffrés, au moins `max_request_bytes`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "max_session_lifetime": {
              "default": "1h",
              "description": "Longest session whatever the credential: a SASL client re-authenticates before it (KIP-368), a connection identified by its certificate is closed; a revocation is seen at the latest then. From `1m` to `24h`, default `1h`.",
              "not": {
                "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
              },
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "Longest session whatever the credential: a SASL client re-authenticates before it (KIP-368), a connection identified by its certificate is closed; a revocation is seen at the latest then. From `1m` to `24h`, default `1h`.",
                "fr": "Durée maximale d'une session quel que soit l'identifiant : un client SASL se réauthentifie avant (KIP-368), une connexion identifiée par certificat est fermée ; une révocation se voit au plus tard alors. De `1m` à `24h`, défaut `1h`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "max_tenant_in_flight_bytes": {
              "anyOf": [
                {
                  "minimum": 1,
                  "type": "integer"
                },
                {
                  "pattern": "^\\s*[1-9][0-9]*\\s*(B|KiB|MiB|GiB)?\\s*$",
                  "type": "string"
                }
              ],
              "description": "The same bound as `max_in_flight_bytes`, for every connection of one tenant: its share of `max_total_in_flight_bytes`; a tenant that does not read never stalls the others. From `max_in_flight_bytes` to `max_total_in_flight_bytes`; absent: an eighth of the total, at least `max_in_flight_bytes`. Read once at start.",
              "x-flexway-description": {
                "en": "The same bound as `max_in_flight_bytes`, for every connection of one tenant: its share of `max_total_in_flight_bytes`; a tenant that does not read never stalls the others. From `max_in_flight_bytes` to `max_total_in_flight_bytes`; absent: an eighth of the total, at least `max_in_flight_bytes`. Read once at start.",
                "fr": "Même borne que `max_in_flight_bytes`, pour toutes les connexions d'un tenant : sa part de `max_total_in_flight_bytes` ; un tenant qui ne lit pas ne bloque jamais les autres. De `max_in_flight_bytes` à `max_total_in_flight_bytes` ; absente : un huitième du total, au moins `max_in_flight_bytes`. Lue une fois au démarrage."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "1.6.0"
            },
            "max_topic_partitions": {
              "default": 64,
              "description": "Partitions an administrator may give a topic (`CreateTopics`, `CreatePartitions`); from 1 to 10000, default `64`.",
              "maximum": 10000,
              "minimum": 1,
              "type": "integer",
              "x-flexway-description": {
                "en": "Partitions an administrator may give a topic (`CreateTopics`, `CreatePartitions`); from 1 to 10000, default `64`.",
                "fr": "Partitions qu'un administrateur peut donner à un sujet (`CreateTopics`, `CreatePartitions`) ; de 1 à 10000, défaut `64`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "max_total_in_flight_bytes": {
              "anyOf": [
                {
                  "minimum": 1,
                  "type": "integer"
                },
                {
                  "pattern": "^\\s*[1-9][0-9]*\\s*(B|KiB|MiB|GiB)?\\s*$",
                  "type": "string"
                }
              ],
              "default": "1GiB",
              "description": "Answers held in memory by the whole replica, all connections together; `64GiB` at most, default `1GiB`. Read once at start.",
              "x-flexway-description": {
                "en": "Answers held in memory by the whole replica, all connections together; `64GiB` at most, default `1GiB`. Read once at start.",
                "fr": "Réponses en mémoire pour toute la réplique, toutes connexions confondues ; `64GiB` au plus, défaut `1GiB`. Lue une fois au démarrage."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "1.6.0"
            },
            "max_unauthenticated_connections": {
              "default": 256,
              "description": "Connections that have not proved who they are yet; past it, a new one is closed at once and authenticated clients keep their places. From 1 to `max_connections`, default `256`.",
              "minimum": 1,
              "type": "integer",
              "x-flexway-description": {
                "en": "Connections that have not proved who they are yet; past it, a new one is closed at once and authenticated clients keep their places. From 1 to `max_connections`, default `256`.",
                "fr": "Connexions qui n'ont pas encore prouvé leur identité ; au-delà, une nouvelle est fermée aussitôt et les clients authentifiés gardent leurs places. De 1 à `max_connections`, défaut `256`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "on_tenant_budget_exceeded": {
              "default": "wait",
              "description": "What happens to a connection whose answer would exceed `max_tenant_in_flight_bytes`: `wait` (default) - the broker is not read until the tenant's clients read - or `close` - the connection ends at once, for tenants not trusted to read. The other tenants are never stalled.",
              "enum": [
                "wait",
                "close"
              ],
              "type": "string",
              "x-flexway-description": {
                "en": "What happens to a connection whose answer would exceed `max_tenant_in_flight_bytes`: `wait` (default) - the broker is not read until the tenant's clients read - or `close` - the connection ends at once, for tenants not trusted to read. The other tenants are never stalled.",
                "fr": "Sort d'une connexion dont la réponse dépasserait `max_tenant_in_flight_bytes` : `wait` (défaut) - le courtier n'est plus lu jusqu'à ce que les clients du tenant lisent - ou `close` - la connexion est fermée aussitôt, pour des tenants dont on ne garantit pas la lecture. Les autres tenants ne sont jamais bloqués."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "plaintext": {
              "additionalProperties": false,
              "description": "Fallback without TLS: a bootstrap port and a port per broker for each virtual cluster, only where a mesh already encrypts between pods (`mesh_only: true` required). Read once at start.",
              "properties": {
                "advertised_host": {
                  "description": "Host written into the broker addresses a client is given: the gateway's `Service` name in the mesh, without a port. Required.",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "Host written into the broker addresses a client is given: the gateway's `Service` name in the mesh, without a port. Required.",
                    "fr": "Hôte écrit dans les adresses de courtier données au client : le nom du `Service` de la passerelle dans le maillage, sans port. Obligatoire."
                  },
                  "x-flexway-reloadable": false,
                  "x-flexway-since": "1.6.0"
                },
                "clusters": {
                  "additionalProperties": {
                    "additionalProperties": false,
                    "properties": {
                      "first_node_id": {
                        "description": "Node id of the first broker: port `from + 1 + i` serves node `first_node_id + i`. A non-negative integer, default `0`.",
                        "minimum": 0,
                        "type": "integer",
                        "x-flexway-description": {
                          "en": "Node id of the first broker: port `from + 1 + i` serves node `first_node_id + i`. A non-negative integer, default `0`.",
                          "fr": "Identifiant de nœud du premier courtier : le port `from + 1 + i` sert le nœud `first_node_id + i`. Entier positif ou nul, défaut `0`."
                        },
                        "x-flexway-reloadable": false,
                        "x-flexway-since": "1.6.0"
                      },
                      "ports": {
                        "additionalProperties": false,
                        "description": "Closed range of the cluster's ports: `from` is the bootstrap, then one port per broker up to `to`; 65 ports at most, never shared with another cluster nor with `address`.",
                        "properties": {
                          "from": {
                            "description": "The cluster's bootstrap port; from 1 to 65535.",
                            "maximum": 65535,
                            "minimum": 1,
                            "type": "integer",
                            "x-flexway-description": {
                              "en": "The cluster's bootstrap port; from 1 to 65535.",
                              "fr": "Port d'amorçage du cluster ; de 1 à 65535."
                            },
                            "x-flexway-reloadable": false,
                            "x-flexway-since": "1.6.0"
                          },
                          "to": {
                            "description": "Last port of the range, greater than `from`; 65535 at most.",
                            "maximum": 65535,
                            "minimum": 1,
                            "type": "integer",
                            "x-flexway-description": {
                              "en": "Last port of the range, greater than `from`; 65535 at most.",
                              "fr": "Dernier port de la plage, plus grand que `from` ; 65535 au plus."
                            },
                            "x-flexway-reloadable": false,
                            "x-flexway-since": "1.6.0"
                          }
                        },
                        "type": "object",
                        "x-flexway-description": {
                          "en": "Closed range of the cluster's ports: `from` is the bootstrap, then one port per broker up to `to`; 65 ports at most, never shared with another cluster nor with `address`.",
                          "fr": "Plage fermée des ports du cluster : `from` est l'amorçage, puis un port par courtier jusqu'à `to` ; 65 ports au plus, jamais partagés avec un autre cluster ni avec `address`."
                        },
                        "x-flexway-reloadable": false,
                        "x-flexway-since": "1.6.0"
                      }
                    },
                    "type": "object"
                  },
                  "description": "The ports of each virtual cluster, by cluster name (a DNS label: lower-case letters, digits, `-`); at least one.",
                  "type": "object",
                  "x-flexway-description": {
                    "en": "The ports of each virtual cluster, by cluster name (a DNS label: lower-case letters, digits, `-`); at least one.",
                    "fr": "Les ports de chaque cluster virtuel, par nom de cluster (un label DNS : minuscules, chiffres, `-`) ; au moins un."
                  },
                  "x-flexway-reloadable": false,
                  "x-flexway-since": "1.6.0"
                },
                "mesh_only": {
                  "description": "Must be `true`: states that a mesh encrypts between pods. Without it, a Kafka client's credentials would cross the network in clear, and the configuration is refused.",
                  "type": "boolean",
                  "x-flexway-description": {
                    "en": "Must be `true`: states that a mesh encrypts between pods. Without it, a Kafka client's credentials would cross the network in clear, and the configuration is refused.",
                    "fr": "Doit valoir `true` : affirme qu'un maillage chiffre entre pods. Sans lui, les identifiants d'un client Kafka traverseraient le réseau en clair, et la configuration est refusée."
                  },
                  "x-flexway-reloadable": false,
                  "x-flexway-since": "1.6.0"
                }
              },
              "type": "object",
              "x-flexway-description": {
                "en": "Fallback without TLS: a bootstrap port and a port per broker for each virtual cluster, only where a mesh already encrypts between pods (`mesh_only: true` required). Read once at start.",
                "fr": "Repli sans TLS : un port d'amorçage et un port par courtier pour chaque cluster virtuel, seulement là où un maillage chiffre déjà entre pods (`mesh_only: true` obligatoire). Lu une fois au démarrage."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "1.6.0"
            },
            "quotas": {
              "additionalProperties": false,
              "description": "Byte and request quotas per verified principal and per tenant, as a Kafka broker applies them (KIP-219): the answer leaves at once with `throttle_time_ms`, then the connection is not read for that long. Absent: nothing is throttled.",
              "properties": {
                "client": {
                  "additionalProperties": false,
                  "description": "Rates of each verified principal - the token's subject, the API key, the certificate -, never the `client.id` a client names itself with. No bound by default.",
                  "properties": {
                    "consumer_byte_rate": {
                      "anyOf": [
                        {
                          "minimum": 1,
                          "type": "integer"
                        },
                        {
                          "pattern": "^\\s*[1-9][0-9]*\\s*(B|KiB|MiB|GiB)?\\s*$",
                          "type": "string"
                        }
                      ],
                      "description": "Bytes read per second (`Fetch` answers) per principal; a size (`10MiB`), 0 or absent: no bound.",
                      "x-flexway-description": {
                        "en": "Bytes read per second (`Fetch` answers) per principal; a size (`10MiB`), 0 or absent: no bound.",
                        "fr": "Octets lus par seconde (réponses `Fetch`) par principal ; une taille (`10MiB`), 0 ou absent : sans borne."
                      },
                      "x-flexway-reloadable": true,
                      "x-flexway-since": "1.6.0"
                    },
                    "producer_byte_rate": {
                      "anyOf": [
                        {
                          "minimum": 1,
                          "type": "integer"
                        },
                        {
                          "pattern": "^\\s*[1-9][0-9]*\\s*(B|KiB|MiB|GiB)?\\s*$",
                          "type": "string"
                        }
                      ],
                      "description": "Bytes produced per second (`Produce` requests) per principal; a size (`10MiB`), 0 or absent: no bound.",
                      "x-flexway-description": {
                        "en": "Bytes produced per second (`Produce` requests) per principal; a size (`10MiB`), 0 or absent: no bound.",
                        "fr": "Octets produits par seconde (requêtes `Produce`) par principal ; une taille (`10MiB`), 0 ou absent : sans borne."
                      },
                      "x-flexway-reloadable": true,
                      "x-flexway-since": "1.6.0"
                    },
                    "request_rate": {
                      "description": "Requests per second per principal, whatever the API; a non-negative number, 0 or absent: no bound.",
                      "minimum": 0,
                      "type": "number",
                      "x-flexway-description": {
                        "en": "Requests per second per principal, whatever the API; a non-negative number, 0 or absent: no bound.",
                        "fr": "Requêtes par seconde par principal, quelle que soit l'API ; nombre positif, 0 ou absent : sans borne."
                      },
                      "x-flexway-reloadable": true,
                      "x-flexway-since": "1.6.0"
                    }
                  },
                  "type": "object",
                  "x-flexway-description": {
                    "en": "Rates of each verified principal - the token's subject, the API key, the certificate -, never the `client.id` a client names itself with. No bound by default.",
                    "fr": "Débits de chaque principal vérifié - sujet du jeton, clé d'API, certificat -, jamais le `client.id` qu'un client se donne. Aucune borne par défaut."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "max_throttle": {
                  "default": "10s",
                  "description": "Cap of the announced `throttle_time_ms` and of the silence that follows, below the clients' `request.timeout.ms`; from `100ms` to `30s`, default `10s`.",
                  "not": {
                    "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
                  },
                  "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "Cap of the announced `throttle_time_ms` and of the silence that follows, below the clients' `request.timeout.ms`; from `100ms` to `30s`, default `10s`.",
                    "fr": "Plafond du `throttle_time_ms` annoncé et du silence qui suit, sous le `request.timeout.ms` des clients ; de `100ms` à `30s`, défaut `10s`."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "quota": {
                  "description": "Name of a policy of type `quota` in `policies.definitions`: the tenant's day or month budget of `Produce` requests, shared with HTTP under the same name; spent: `POLICY_VIOLATION`. Empty: none.",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "Name of a policy of type `quota` in `policies.definitions`: the tenant's day or month budget of `Produce` requests, shared with HTTP under the same name; spent: `POLICY_VIOLATION`. Empty: none.",
                    "fr": "Nom d'une politique de type `quota` de `policies.definitions` : le budget jour ou mois des `Produce` du tenant, partagé avec HTTP sous le même nom ; épuisé : `POLICY_VIOLATION`. Vide : aucun."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "tenant": {
                  "additionalProperties": false,
                  "description": "Rates of every principal of one tenant together. No bound by default.",
                  "properties": {
                    "consumer_byte_rate": {
                      "anyOf": [
                        {
                          "minimum": 1,
                          "type": "integer"
                        },
                        {
                          "pattern": "^\\s*[1-9][0-9]*\\s*(B|KiB|MiB|GiB)?\\s*$",
                          "type": "string"
                        }
                      ],
                      "description": "Bytes read per second per tenant; a size, 0 or absent: no bound.",
                      "x-flexway-description": {
                        "en": "Bytes read per second per tenant; a size, 0 or absent: no bound.",
                        "fr": "Octets lus par seconde par tenant ; une taille, 0 ou absent : sans borne."
                      },
                      "x-flexway-reloadable": true,
                      "x-flexway-since": "1.6.0"
                    },
                    "producer_byte_rate": {
                      "anyOf": [
                        {
                          "minimum": 1,
                          "type": "integer"
                        },
                        {
                          "pattern": "^\\s*[1-9][0-9]*\\s*(B|KiB|MiB|GiB)?\\s*$",
                          "type": "string"
                        }
                      ],
                      "description": "Bytes produced per second per tenant; a size, 0 or absent: no bound.",
                      "x-flexway-description": {
                        "en": "Bytes produced per second per tenant; a size, 0 or absent: no bound.",
                        "fr": "Octets produits par seconde par tenant ; une taille, 0 ou absent : sans borne."
                      },
                      "x-flexway-reloadable": true,
                      "x-flexway-since": "1.6.0"
                    },
                    "request_rate": {
                      "description": "Requests per second per tenant, whatever the API; 0 or absent: no bound.",
                      "minimum": 0,
                      "type": "number",
                      "x-flexway-description": {
                        "en": "Requests per second per tenant, whatever the API; 0 or absent: no bound.",
                        "fr": "Requêtes par seconde par tenant, quelle que soit l'API ; 0 ou absent : sans borne."
                      },
                      "x-flexway-reloadable": true,
                      "x-flexway-since": "1.6.0"
                    }
                  },
                  "type": "object",
                  "x-flexway-description": {
                    "en": "Rates of every principal of one tenant together. No bound by default.",
                    "fr": "Débits de tous les principaux d'un même tenant ensemble. Aucune borne par défaut."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "window": {
                  "default": "1s",
                  "description": "How much of a rate a burst may take at once: a bucket holds rate x window; from `100ms` to `10s`, default `1s`.",
                  "not": {
                    "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
                  },
                  "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "How much of a rate a burst may take at once: a bucket holds rate x window; from `100ms` to `10s`, default `1s`.",
                    "fr": "Part d'un débit qu'une rafale peut prendre d'un coup : un seau contient débit x fenêtre ; de `100ms` à `10s`, défaut `1s`."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                }
              },
              "type": "object",
              "x-flexway-description": {
                "en": "Byte and request quotas per verified principal and per tenant, as a Kafka broker applies them (KIP-219): the answer leaves at once with `throttle_time_ms`, then the connection is not read for that long. Absent: nothing is throttled.",
                "fr": "Quotas d'octets et de requêtes par principal vérifié et par tenant, comme un courtier Kafka (KIP-219) : la réponse part aussitôt avec `throttle_time_ms`, puis la connexion n'est plus lue pendant ce délai. Absent : rien n'est freiné."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "sni_domain": {
              "description": "DNS domain the broker names live under (`kafka.example.com`): `bootstrap.<cluster>.<sni_domain>` and `broker-<id>.<cluster>.<sni_domain>`. At least two labels, lower-case; required with `address`.",
              "type": "string",
              "x-flexway-description": {
                "en": "DNS domain the broker names live under (`kafka.example.com`): `bootstrap.<cluster>.<sni_domain>` and `broker-<id>.<cluster>.<sni_domain>`. At least two labels, lower-case; required with `address`.",
                "fr": "Domaine DNS sous lequel vivent les noms de courtier (`kafka.example.com`) : `bootstrap.<cluster>.<sni_domain>` et `broker-<id>.<cluster>.<sni_domain>`. Au moins deux labels, en minuscules ; obligatoire avec `address`."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "1.6.0"
            },
            "tls": {
              "additionalProperties": false,
              "description": "Certificate of the TLS listener - one covering `*.<cluster>.<sni_domain>` for every cluster - and, with `client_ca_file`, the authority of client certificates. Required with `address`, refused without it.",
              "properties": {
                "cert_file": {
                  "description": "The listener's certificate (PEM); required, the file must exist.",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "The listener's certificate (PEM); required, the file must exist.",
                    "fr": "Certificat PEM de l'écouteur ; obligatoire, le fichier doit exister."
                  },
                  "x-flexway-reloadable": false,
                  "x-flexway-since": "1.6.0"
                },
                "client_ca_file": {
                  "description": "PEM authority client certificates are verified against (the `X509` identity); optional, the file must exist.",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "PEM authority client certificates are verified against (the `X509` identity); optional, the file must exist.",
                    "fr": "Autorité PEM contre laquelle les certificats clients sont vérifiés (identité `X509`) ; facultative, le fichier doit exister."
                  },
                  "x-flexway-reloadable": false,
                  "x-flexway-since": "1.6.0"
                },
                "key_file": {
                  "description": "Private key (PEM) of the listener's certificate; required, the file must exist.",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "Private key (PEM) of the listener's certificate; required, the file must exist.",
                    "fr": "Clé privée PEM du certificat de l'écouteur ; obligatoire, le fichier doit exister."
                  },
                  "x-flexway-reloadable": false,
                  "x-flexway-since": "1.6.0"
                }
              },
              "type": "object",
              "x-flexway-description": {
                "en": "Certificate of the TLS listener - one covering `*.<cluster>.<sni_domain>` for every cluster - and, with `client_ca_file`, the authority of client certificates. Required with `address`, refused without it.",
                "fr": "Certificat de l'écouteur TLS - un certificat qui couvre `*.<cluster>.<sni_domain>` pour chaque cluster - et, avec `client_ca_file`, l'autorité des certificats clients. Obligatoire avec `address`, refusé sans lui."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "1.6.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "The Kafka listener: Kafka producers, consumers and admin tools reach the virtual clusters the AsyncAPI contract declares (`x-flexway-kafka-proxy`), under the same decision as HTTP. Nothing here lists a topic: the contract does. One TLS port, the broker named by the client's SNI (`address`), or plaintext ports inside a mesh (`plaintext`); requires `contracts.asyncapi`.",
            "fr": "L'écouteur Kafka : producteurs, consommateurs et outils d'administration Kafka atteignent les clusters virtuels que le contrat AsyncAPI déclare (`x-flexway-kafka-proxy`), sous la même décision que HTTP. Rien ici ne liste un sujet : le contrat le fait. Un port TLS, le courtier nommé par le SNI du client (`address`), ou des ports en clair dans un maillage (`plaintext`) ; exige `contracts.asyncapi`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        },
        "mqtt": {
          "additionalProperties": false,
          "description": "The MQTT device listener: devices connect in MQTT 5 or 3.1.1 over TCP, TLS or WebSocket and reach the customer's broker through it, one broker connection per device, every packet under the same decision as HTTP. Nothing here lists a topic: the AsyncAPI contract does (`x-flexway-device`). Requires `contracts.asyncapi`.",
          "properties": {
            "address": {
              "description": "The listener's `host:port` address (`:8883`); TLS when `tls` is set. Read once at start.",
              "type": "string",
              "x-flexway-description": {
                "en": "The listener's `host:port` address (`:8883`); TLS when `tls` is set. Read once at start.",
                "fr": "Adresse `hôte:port` de l'écouteur (`:8883`) ; TLS quand `tls` est renseigné. Lue une seule fois au démarrage."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "advertised_address": {
              "description": "The `host:port` devices reach the listener at - the load balancer's: the default `failover.server_reference`.",
              "type": "string",
              "x-flexway-description": {
                "en": "The `host:port` devices reach the listener at - the load balancer's: the default `failover.server_reference`.",
                "fr": "Adresse `hôte:port` où les appareils joignent l'écouteur - celle de l'équilibreur : la `failover.server_reference` par défaut."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "allow_zero_keepalive": {
              "description": "Admits an MQTT 3.1.1 device asking no keep-alive (`0`). `false` (the default): it is refused (return code `0x05`), like one asking more than `max_keepalive` - MQTT 3.1.1 cannot be told a keep-alive, and a silent device would never be seen gone. MQTT 5 is told `max_keepalive` instead.",
              "type": "boolean",
              "x-flexway-description": {
                "en": "Admits an MQTT 3.1.1 device asking no keep-alive (`0`). `false` (the default): it is refused (return code `0x05`), like one asking more than `max_keepalive` - MQTT 3.1.1 cannot be told a keep-alive, and a silent device would never be seen gone. MQTT 5 is told `max_keepalive` instead.",
                "fr": "Admet un appareil MQTT 3.1.1 qui ne demande aucun keep-alive (`0`). `false` (défaut) : il est refusé (code `0x05`), comme celui qui demande plus que `max_keepalive` - MQTT 3.1.1 ne permet pas d'imposer un keep-alive, et un appareil muet ne serait jamais vu parti. Un appareil MQTT 5 reçoit `max_keepalive` à la place."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "broker_mesh_only": {
              "description": "Admits brokers in clear (`mqtt://`, `ws://`) when the listener itself is in TLS: the mesh encrypts the hop to the broker. `false` (the default): a broker in clear is refused at load unless `mesh_only` is set.",
              "type": "boolean",
              "x-flexway-description": {
                "en": "Admits brokers in clear (`mqtt://`, `ws://`) when the listener itself is in TLS: the mesh encrypts the hop to the broker. `false` (the default): a broker in clear is refused at load unless `mesh_only` is set.",
                "fr": "Admet des courtiers en clair (`mqtt://`, `ws://`) quand l'écouteur lui-même est en TLS : le maillage chiffre le saut vers le courtier. `false` (défaut) : un courtier en clair est refusé au chargement sauf avec `mesh_only`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "connect_timeout": {
              "description": "Time a connection has to complete TLS and send its CONNECT, and the broker to answer; more than 0 and `1m` at most, default `5s`.",
              "not": {
                "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
              },
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "Time a connection has to complete TLS and send its CONNECT, and the broker to answer; more than 0 and `1m` at most, default `5s`.",
                "fr": "Temps laissé à une connexion pour finir TLS et envoyer son CONNECT, et au courtier pour répondre ; plus de 0 et `1m` au plus, défaut `5s`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "device": {
              "additionalProperties": false,
              "description": "Bounds of each device connection; an operation's `x-flexway-device` overrides its rates.",
              "properties": {
                "burst": {
                  "description": "Seconds of each rate a burst may take at once; from 1 to 60, default 2.",
                  "type": "number",
                  "x-flexway-description": {
                    "en": "Seconds of each rate a burst may take at once; from 1 to 60, default 2.",
                    "fr": "Secondes de chaque débit qu'une rafale peut prendre d'un coup ; de 1 à 60, défaut 2."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "bytes_per_second": {
                  "anyOf": [
                    {
                      "minimum": 1,
                      "type": "integer"
                    },
                    {
                      "pattern": "^\\s*[1-9][0-9]*\\s*(B|KiB|MiB|GiB)?\\s*$",
                      "type": "string"
                    }
                  ],
                  "description": "PUBLISH payload bytes a device sends per second, under the same backpressure. `0`: none. Default 512 KiB.",
                  "x-flexway-description": {
                    "en": "PUBLISH payload bytes a device sends per second, under the same backpressure. `0`: none. Default 512 KiB.",
                    "fr": "Octets de charge des PUBLISH d'un appareil par seconde, sous la même contre-pression. `0` : aucune borne. Défaut 512 Kio."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "connect_rate_per_identity": {
                  "description": "CONNECT of one identity per second; past it `0x9F`: a device that reconnects in a loop never evicts itself again and again. `0`: none. Default 1.",
                  "type": "number",
                  "x-flexway-description": {
                    "en": "CONNECT of one identity per second; past it `0x9F`: a device that reconnects in a loop never evicts itself again and again. `0`: none. Default 1.",
                    "fr": "CONNECT d'une identité par seconde ; au-delà `0x9F` : un appareil qui se reconnecte en boucle ne s'évince pas lui-même sans fin. `0` : aucune borne. Défaut 1."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "max_correlation_data_bytes": {
                  "anyOf": [
                    {
                      "minimum": 1,
                      "type": "integer"
                    },
                    {
                      "pattern": "^\\s*[1-9][0-9]*\\s*(B|KiB|MiB|GiB)?\\s*$",
                      "type": "string"
                    }
                  ],
                  "description": "Bytes of a PUBLISH's correlation data; past it `0x95`. Default 8 KiB.",
                  "x-flexway-description": {
                    "en": "Bytes of a PUBLISH's correlation data; past it `0x95`. Default 8 KiB.",
                    "fr": "Octets de la donnée de corrélation d'un PUBLISH ; au-delà `0x95`. Défaut 8 Kio."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "max_filters_per_subscribe": {
                  "description": "Filters of one SUBSCRIBE; past it each is refused `0x97`. Default 10.",
                  "type": "integer",
                  "x-flexway-description": {
                    "en": "Filters of one SUBSCRIBE; past it each is refused `0x97`. Default 10.",
                    "fr": "Filtres d'un SUBSCRIBE ; au-delà chacun est refusé `0x97`. Défaut 10."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "max_refusals_per_minute": {
                  "description": "Refused packets of one connection in a minute: each refusal spends the device's message rate, its audit is sampled (one entry a second per cause), and past this count the device is disconnected `0x96`. `0`: no bound. From 0 to 100000, default 60.",
                  "type": "integer",
                  "x-flexway-description": {
                    "en": "Refused packets of one connection in a minute: each refusal spends the device's message rate, its audit is sampled (one entry a second per cause), and past this count the device is disconnected `0x96`. `0`: no bound. From 0 to 100000, default 60.",
                    "fr": "Paquets refusés d'une connexion en une minute : chaque refus dépense le débit de messages de l'appareil, son audit est échantillonné (une entrée par seconde et par cause), et au-delà de ce nombre l'appareil est déconnecté `0x96`. `0` : sans borne. De 0 à 100000, défaut 60."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "max_sessions_per_identity": {
                  "description": "Connections one identity holds at once on a replica with `sessions: per_client_id`; past it a new one is refused `0x97` (3.1.1: `0x03`). From 1 to `max_connections`, default 10 (or `max_connections` if lower).",
                  "type": "integer",
                  "x-flexway-description": {
                    "en": "Connections one identity holds at once on a replica with `sessions: per_client_id`; past it a new one is refused `0x97` (3.1.1: `0x03`). From 1 to `max_connections`, default 10 (or `max_connections` if lower).",
                    "fr": "Connexions qu'une identité tient à la fois sur un réplica avec `sessions: per_client_id` ; au-delà une nouvelle est refusée `0x97` (3.1.1 : `0x03`). De 1 à `max_connections`, défaut 10 (ou `max_connections` s'il est plus bas)."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "max_subscriptions": {
                  "description": "Subscriptions of a device; past it a filter is refused `0x97` (3.1.1 `0x80`). Default 50.",
                  "type": "integer",
                  "x-flexway-description": {
                    "en": "Subscriptions of a device; past it a filter is refused `0x97` (3.1.1 `0x80`). Default 50.",
                    "fr": "Abonnements d'un appareil ; au-delà un filtre est refusé `0x97` (3.1.1 `0x80`). Défaut 50."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "max_user_properties_bytes": {
                  "anyOf": [
                    {
                      "minimum": 1,
                      "type": "integer"
                    },
                    {
                      "pattern": "^\\s*[1-9][0-9]*\\s*(B|KiB|MiB|GiB)?\\s*$",
                      "type": "string"
                    }
                  ],
                  "description": "Bytes of the user properties of a packet; past it `0x95`. Default 8 KiB.",
                  "x-flexway-description": {
                    "en": "Bytes of the user properties of a packet; past it `0x95`. Default 8 KiB.",
                    "fr": "Octets des propriétés utilisateur d'un paquet ; au-delà `0x95`. Défaut 8 Kio."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "messages_per_second": {
                  "description": "PUBLISH a device sends per second; past it the listener stops reading the device (backpressure, never a refusal) and keeps its broker connection alive meanwhile. `0`: none. Default 100.",
                  "type": "number",
                  "x-flexway-description": {
                    "en": "PUBLISH a device sends per second; past it the listener stops reading the device (backpressure, never a refusal) and keeps its broker connection alive meanwhile. `0`: none. Default 100.",
                    "fr": "PUBLISH envoyés par seconde par un appareil ; au-delà l'écouteur cesse de lire l'appareil (contre-pression, jamais un refus) et garde vivante sa connexion au courtier. `0` : aucune borne. Défaut 100."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "receive_maximum": {
                  "description": "QoS 1 and 2 PUBLISH in flight from a device, announced as the lower of it and the broker's; past it `0x93`. Default 100.",
                  "type": "integer",
                  "x-flexway-description": {
                    "en": "QoS 1 and 2 PUBLISH in flight from a device, announced as the lower of it and the broker's; past it `0x93`. Default 100.",
                    "fr": "PUBLISH QoS 1 et 2 en vol d'un appareil, annoncé comme le plus bas de lui et du courtier ; au-delà `0x93`. Défaut 100."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "sessions": {
                  "description": "Sessions of one identity: `single` (the default) - client id `<tenant>/<identity>` at the broker, a second connection evicts the first (`0x8E`) -, or `per_client_id` - `<tenant>/<identity>/<the device's client id>`, for an identity several devices share.",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "Sessions of one identity: `single` (the default) - client id `<tenant>/<identity>` at the broker, a second connection evicts the first (`0x8E`) -, or `per_client_id` - `<tenant>/<identity>/<the device's client id>`, for an identity several devices share.",
                    "fr": "Sessions d'une identité : `single` (défaut) - client id `<tenant>/<identité>` au courtier, une seconde connexion évince la première (`0x8E`) -, ou `per_client_id` - `<tenant>/<identité>/<client id de l'appareil>`, pour une identité que plusieurs appareils partagent."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                }
              },
              "type": "object",
              "x-flexway-description": {
                "en": "Bounds of each device connection; an operation's `x-flexway-device` overrides its rates.",
                "fr": "Bornes de chaque connexion d'appareil ; le `x-flexway-device` d'une opération surcharge ses débits."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "failover": {
              "additionalProperties": false,
              "description": "Moves the devices of a replica that drains or is full to another one: MQTT 5 is told where to go, 3.1.1 reconnects through the load balancer.",
              "properties": {
                "handover_timeout": {
                  "description": "Time a draining replica holds a device's broker connection for it to come back elsewhere; past it the connection closes with the will. From `0s` to `10m`, default `30s`.",
                  "not": {
                    "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
                  },
                  "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "Time a draining replica holds a device's broker connection for it to come back elsewhere; past it the connection closes with the will. From `0s` to `10m`, default `30s`.",
                    "fr": "Temps pendant lequel une réplique qui draine tient la connexion au courtier d'un appareil pour qu'il revienne ailleurs ; au-delà elle se ferme avec le testament. De `0s` à `10m`, défaut `30s`."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "mode": {
                  "description": "`redirect` (the default): `0x9C` (or `0x9D`) and a Server Reference, the broker connection held `handover_timeout` for the device to come back through another replica; `off`: a drain sends `0x8B` and closes the broker connection with the will.",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "`redirect` (the default): `0x9C` (or `0x9D`) and a Server Reference, the broker connection held `handover_timeout` for the device to come back through another replica; `off`: a drain sends `0x8B` and closes the broker connection with the will.",
                    "fr": "`redirect` (défaut) : `0x9C` (ou `0x9D`) et une Server Reference, la connexion au courtier tenue `handover_timeout` pour que l'appareil revienne par une autre réplique ; `off` : un arrêt envoie `0x8B` et ferme la connexion au courtier avec le testament."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "reason": {
                  "description": "`use_another_server` (`0x9C`, temporary, the default) or `server_moved` (`0x9D`, permanent).",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "`use_another_server` (`0x9C`, temporary, the default) or `server_moved` (`0x9D`, permanent).",
                    "fr": "`use_another_server` (`0x9C`, temporaire, défaut) ou `server_moved` (`0x9D`, permanent)."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "redirect_above": {
                  "description": "Share of `max_connections`, in percent, past which a CONNECT is redirected rather than accepted. Default 95.",
                  "type": "number",
                  "x-flexway-description": {
                    "en": "Share of `max_connections`, in percent, past which a CONNECT is redirected rather than accepted. Default 95.",
                    "fr": "Part de `max_connections`, en pourcentage, au-delà de laquelle un CONNECT est redirigé plutôt qu'accepté. Défaut 95."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "server_reference": {
                  "description": "Where a redirected device goes; default `advertised_address` - a client that ignores it reconnects to the same place anyway.",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "Where a redirected device goes; default `advertised_address` - a client that ignores it reconnects to the same place anyway.",
                    "fr": "Où va un appareil redirigé ; défaut `advertised_address` - un client qui l'ignore se reconnecte au même endroit de toute façon."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "will_delay_on_handover": {
                  "description": "Toward an MQTT 5 broker, a will that declares no Will Delay Interval is written with one equal to `handover_timeout`, and the broker session's expiry raised to cover it: the will survives a takeover by another replica. The cost: the will of a device really lost goes up to `handover_timeout` later. No effect on an MQTT 3.1.1 device. Default `false`.",
                  "type": "boolean",
                  "x-flexway-description": {
                    "en": "Toward an MQTT 5 broker, a will that declares no Will Delay Interval is written with one equal to `handover_timeout`, and the broker session's expiry raised to cover it: the will survives a takeover by another replica. The cost: the will of a device really lost goes up to `handover_timeout` later. No effect on an MQTT 3.1.1 device. Default `false`.",
                    "fr": "Vers un courtier MQTT 5, un testament qui ne déclare aucun délai (Will Delay Interval) est écrit avec un délai égal à `handover_timeout`, et l'expiration de la session au courtier relevée pour le couvrir : le testament survit à une reprise par une autre réplique. La contrepartie : le testament d'un appareil vraiment perdu part jusqu'à `handover_timeout` plus tard. Sans effet sur un appareil MQTT 3.1.1. Défaut `false`."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                }
              },
              "type": "object",
              "x-flexway-description": {
                "en": "Moves the devices of a replica that drains or is full to another one: MQTT 5 is told where to go, 3.1.1 reconnects through the load balancer.",
                "fr": "Bascule les appareils d'une réplique qui draine ou est pleine vers une autre : MQTT 5 est dirigé, 3.1.1 se reconnecte par l'équilibreur."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "max_connection_rate_per_ip": {
              "description": "New connections of one client address per second; `0`: none. Default 20.",
              "type": "number",
              "x-flexway-description": {
                "en": "New connections of one client address per second; `0`: none. Default 20.",
                "fr": "Nouvelles connexions d'une adresse cliente par seconde ; `0` : aucune borne. Défaut 20."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "max_connection_rate_per_tenant": {
              "description": "New device connections of one tenant per second; past it `0x9F` (3.1.1 `0x03`). `0`: none. Default 100.",
              "type": "number",
              "x-flexway-description": {
                "en": "New device connections of one tenant per second; past it `0x9F` (3.1.1 `0x03`). `0`: none. Default 100.",
                "fr": "Nouvelles connexions d'appareils d'un tenant par seconde ; au-delà `0x9F` (3.1.1 `0x03`). `0` : aucune borne. Défaut 100."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "max_connections": {
              "description": "Device connections of a replica; past it a CONNECT is refused `0x97` (3.1.1 `0x03`). From 1 to 1000000, default 50000. Read once at start.",
              "type": "integer",
              "x-flexway-description": {
                "en": "Device connections of a replica; past it a CONNECT is refused `0x97` (3.1.1 `0x03`). From 1 to 1000000, default 50000. Read once at start.",
                "fr": "Connexions d'appareils d'une réplique ; au-delà un CONNECT est refusé `0x97` (3.1.1 `0x03`). De 1 à 1000000, défaut 50000. Lu une seule fois au démarrage."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "max_connections_per_ip": {
              "description": "Connections of one client address; `0`: none - set it behind a load balancer or proxy that hides the devices' addresses (the chart keeps them with `externalTrafficPolicy: Local`), or every device shares one address and one bound. Default 64.",
              "type": "integer",
              "x-flexway-description": {
                "en": "Connections of one client address; `0`: none - set it behind a load balancer or proxy that hides the devices' addresses (the chart keeps them with `externalTrafficPolicy: Local`), or every device shares one address and one bound. Default 64.",
                "fr": "Connexions d'une adresse cliente ; `0` : aucune borne - à poser derrière un répartiteur ou un proxy qui masque les adresses des appareils (le chart les garde avec `externalTrafficPolicy: Local`), sinon tous les appareils partagent une adresse et une borne. Défaut 64."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "max_connections_per_tenant": {
              "description": "Device connections of one tenant on a replica; past it `0x97`. Default 10000.",
              "type": "integer",
              "x-flexway-description": {
                "en": "Device connections of one tenant on a replica; past it `0x97`. Default 10000.",
                "fr": "Connexions d'appareils d'un tenant sur une réplique ; au-delà `0x97`. Défaut 10000."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "max_keepalive": {
              "description": "Highest keep-alive a device gets: an MQTT 5 device asking more (or none) is told this one (Server Keep Alive); an MQTT 3.1.1 device asking more is refused (`0x05`), none too unless `allow_zero_keepalive`. From `1s` to `65535s`, default `1200s`.",
              "not": {
                "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
              },
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "Highest keep-alive a device gets: an MQTT 5 device asking more (or none) is told this one (Server Keep Alive); an MQTT 3.1.1 device asking more is refused (`0x05`), none too unless `allow_zero_keepalive`. From `1s` to `65535s`, default `1200s`.",
                "fr": "Keep-alive le plus haut accordé : un appareil MQTT 5 qui demande plus (ou rien) reçoit celui-ci (Server Keep Alive) ; un appareil MQTT 3.1.1 qui demande plus est refusé (`0x05`), rien aussi sauf avec `allow_zero_keepalive`. De `1s` à `65535s`, défaut `1200s`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "max_packet_bytes": {
              "anyOf": [
                {
                  "minimum": 1,
                  "type": "integer"
                },
                {
                  "pattern": "^\\s*[1-9][0-9]*\\s*(B|KiB|MiB|GiB)?\\s*$",
                  "type": "string"
                }
              ],
              "description": "Bound of a packet, read whole before it is decoded; announced to an MQTT 5 device as the lower of it and the broker's Maximum Packet Size. From 1 KiB to 256 MiB, default 256 KiB.",
              "x-flexway-description": {
                "en": "Bound of a packet, read whole before it is decoded; announced to an MQTT 5 device as the lower of it and the broker's Maximum Packet Size. From 1 KiB to 256 MiB, default 256 KiB.",
                "fr": "Borne d'un paquet, lu en entier avant d'être décodé ; annoncée à un appareil MQTT 5 comme la plus basse d'elle et du Maximum Packet Size du courtier. De 1 Kio à 256 Mio, défaut 256 Kio."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "max_session_expiry": {
              "description": "Highest session expiry a device's session gets at the broker. Default `1h`.",
              "not": {
                "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
              },
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "Highest session expiry a device's session gets at the broker. Default `1h`.",
                "fr": "Expiration de session la plus longue accordée au courtier. Défaut `1h`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "max_session_lifetime": {
              "description": "Longest device connection whatever its credential: past it the device is disconnected and reconnects with a credential checked again. From `1m` to `30d`, default `24h`.",
              "not": {
                "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
              },
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "Longest device connection whatever its credential: past it the device is disconnected and reconnects with a credential checked again. From `1m` to `30d`, default `24h`.",
                "fr": "Durée la plus longue d'une connexion d'appareil quel que soit son identifiant : au-delà l'appareil est déconnecté et se reconnecte avec un identifiant vérifié à nouveau. De `1m` à `30d`, défaut `24h`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "max_unauthenticated_connections": {
              "description": "Connections that have not sent their CONNECT yet; past it a new one is closed at once. From 1 to `max_connections`, default 1024.",
              "type": "integer",
              "x-flexway-description": {
                "en": "Connections that have not sent their CONNECT yet; past it a new one is closed at once. From 1 to `max_connections`, default 1024.",
                "fr": "Connexions qui n'ont pas encore envoyé leur CONNECT ; au-delà une nouvelle est fermée aussitôt. De 1 à `max_connections`, défaut 1024."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "mesh_only": {
              "description": "Admits the listener without TLS: a device's token or key crosses the network in clear, so it is written only where a mesh encrypts between pods. Refused with `tls`. Default `false`.",
              "type": "boolean",
              "x-flexway-description": {
                "en": "Admits the listener without TLS: a device's token or key crosses the network in clear, so it is written only where a mesh encrypts between pods. Refused with `tls`. Default `false`.",
                "fr": "Admet l'écouteur sans TLS : le jeton ou la clé d'un appareil traverse le réseau en clair, donc ne s'écrit que là où un maillage chiffre entre pods. Refusé avec `tls`. Défaut `false`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "tenant": {
              "additionalProperties": false,
              "description": "Bounds of every device of one tenant together.",
              "properties": {
                "bytes_per_second": {
                  "anyOf": [
                    {
                      "minimum": 1,
                      "type": "integer"
                    },
                    {
                      "pattern": "^\\s*[1-9][0-9]*\\s*(B|KiB|MiB|GiB)?\\s*$",
                      "type": "string"
                    }
                  ],
                  "description": "PUBLISH payload bytes of every device of a tenant per second, under backpressure. `0`: none. Default 20 MiB.",
                  "x-flexway-description": {
                    "en": "PUBLISH payload bytes of every device of a tenant per second, under backpressure. `0`: none. Default 20 MiB.",
                    "fr": "Octets de charge des PUBLISH de tous les appareils d'un tenant par seconde, sous contre-pression. `0` : aucune borne. Défaut 20 Mio."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "messages_per_second": {
                  "description": "PUBLISH of every device of a tenant per second, under backpressure. `0`: none. Default 5000.",
                  "type": "number",
                  "x-flexway-description": {
                    "en": "PUBLISH of every device of a tenant per second, under backpressure. `0`: none. Default 5000.",
                    "fr": "PUBLISH de tous les appareils d'un tenant par seconde, sous contre-pression. `0` : aucune borne. Défaut 5000."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "quota": {
                  "description": "Names a policy of type `quota`: the tenant's day and month budget of PUBLISH, shared with HTTP under that name. Spent: PUBACK `0x97`, QoS 0 dropped and counted, 3.1.1 closed. Absent: none.",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "Names a policy of type `quota`: the tenant's day and month budget of PUBLISH, shared with HTTP under that name. Spent: PUBACK `0x97`, QoS 0 dropped and counted, 3.1.1 closed. Absent: none.",
                    "fr": "Nomme une politique de type `quota` : le budget jour et mois de PUBLISH du tenant, partagé avec HTTP sous ce nom. Épuisé : PUBACK `0x97`, QoS 0 jeté et compté, 3.1.1 fermé. Absent : aucun."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                }
              },
              "type": "object",
              "x-flexway-description": {
                "en": "Bounds of every device of one tenant together.",
                "fr": "Bornes de tous les appareils d'un tenant ensemble."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "tls": {
              "additionalProperties": false,
              "description": "The listener's certificate and, with `client_ca_file`, the authority device certificates are verified against (required by an `X509` alternative). Required unless `mesh_only`. Read once at start.",
              "properties": {
                "cert_file": {
                  "description": "Path of the listener's certificate (PEM).",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "Path of the listener's certificate (PEM).",
                    "fr": "Chemin du certificat de l'écouteur (PEM)."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "client_ca_file": {
                  "description": "Path of the authority device certificates are verified against; absent: no device certificate is verified.",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "Path of the authority device certificates are verified against; absent: no device certificate is verified.",
                    "fr": "Chemin de l'autorité qui vérifie les certificats d'appareil ; absent : aucun certificat d'appareil vérifié."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "key_file": {
                  "description": "Path of the listener's private key (PEM).",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "Path of the listener's private key (PEM).",
                    "fr": "Chemin de la clé privée de l'écouteur (PEM)."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                }
              },
              "type": "object",
              "x-flexway-description": {
                "en": "The listener's certificate and, with `client_ca_file`, the authority device certificates are verified against (required by an `X509` alternative). Required unless `mesh_only`. Read once at start.",
                "fr": "Certificat de l'écouteur et, avec `client_ca_file`, l'autorité qui vérifie les certificats d'appareil (exigée par une alternative `X509`). Obligatoire sauf `mesh_only`. Lu une seule fois au démarrage."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "topic_alias_maximum": {
              "description": "Topic aliases an MQTT 5 device may use toward the listener; an alias is recorded only once its topic is granted, never relayed. `0`: none. At most 1000, default 10.",
              "type": "integer",
              "x-flexway-description": {
                "en": "Topic aliases an MQTT 5 device may use toward the listener; an alias is recorded only once its topic is granted, never relayed. `0`: none. At most 1000, default 10.",
                "fr": "Alias de topic qu'un appareil MQTT 5 peut employer vers l'écouteur ; un alias n'est retenu qu'une fois son topic accordé, jamais relayé. `0` : aucun. Au plus 1000, défaut 10."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "websocket": {
              "additionalProperties": false,
              "description": "MQTT over WebSocket (subprotocol `mqtt`) on an address of its own, with the listener's TLS. Read once at start.",
              "properties": {
                "address": {
                  "description": "The WebSocket listener's `host:port` (`:8884`), not the listener's.",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "The WebSocket listener's `host:port` (`:8884`), not the listener's.",
                    "fr": "Adresse `hôte:port` de l'écouteur WebSocket (`:8884`), pas celle de l'écouteur."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                },
                "path": {
                  "description": "The HTTP path of the WebSocket; default `/mqtt`.",
                  "type": "string",
                  "x-flexway-description": {
                    "en": "The HTTP path of the WebSocket; default `/mqtt`.",
                    "fr": "Chemin HTTP du WebSocket ; défaut `/mqtt`."
                  },
                  "x-flexway-reloadable": true,
                  "x-flexway-since": "1.6.0"
                }
              },
              "type": "object",
              "x-flexway-description": {
                "en": "MQTT over WebSocket (subprotocol `mqtt`) on an address of its own, with the listener's TLS. Read once at start.",
                "fr": "MQTT sur WebSocket (sous-protocole `mqtt`) sur une adresse à lui, avec le TLS de l'écouteur. Lu une seule fois au démarrage."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "The MQTT device listener: devices connect in MQTT 5 or 3.1.1 over TCP, TLS or WebSocket and reach the customer's broker through it, one broker connection per device, every packet under the same decision as HTTP. Nothing here lists a topic: the AsyncAPI contract does (`x-flexway-device`). Requires `contracts.asyncapi`.",
            "fr": "L'écouteur MQTT des appareils : les appareils se connectent en MQTT 5 ou 3.1.1 sur TCP, TLS ou WebSocket et atteignent le courtier du client à travers lui, une connexion au courtier par appareil, chaque paquet sous la même décision que HTTP. Rien ici ne liste un topic : le contrat AsyncAPI le fait (`x-flexway-device`). Exige `contracts.asyncapi`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        }
      },
      "type": "object",
      "x-flexway-description": {
        "en": "The gateway's entry points beside HTTP.",
        "fr": "Les points d'entrée de la passerelle à côté de HTTP."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.6.0"
    },
    "observability": {
      "additionalProperties": false,
      "description": "The gateway's traces, logs and measurements. Without a collector the gateway still starts: a valid configuration, not a degraded one; `/metrics` stays served.",
      "properties": {
        "access_log": {
          "description": "Writes one line per finished request, with the path template - never the path received. Default `false`.",
          "type": "boolean",
          "x-flexway-description": {
            "en": "Writes one line per finished request, with the path template - never the path received. Default `false`.",
            "fr": "Écrit une ligne par requête terminée, avec le gabarit du chemin - jamais le chemin reçu. Défaut `false`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.0.0"
        },
        "kafka": {
          "additionalProperties": false,
          "description": "Measurements of the Kafka listener beyond its fixed instruments.",
          "properties": {
            "budget_wait_buckets": {
              "default": [
                "1ms",
                "5ms",
                "10ms",
                "50ms",
                "100ms",
                "500ms",
                "1s",
                "5s",
                "10s",
                "30s"
              ],
              "description": "Boundaries of the `flexway.kafka.tenant_budget.wait` histogram (a tenant's wait for its share of in-flight bytes): strictly increasing positive durations, 20 at most; default 1 ms to 30 s. Read once at start.",
              "items": {
                "not": {
                  "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
                },
                "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
                "type": "string"
              },
              "maxItems": 20,
              "type": "array",
              "x-flexway-description": {
                "en": "Boundaries of the `flexway.kafka.tenant_budget.wait` histogram (a tenant's wait for its share of in-flight bytes): strictly increasing positive durations, 20 at most; default 1 ms to 30 s. Read once at start.",
                "fr": "Bornes de l'histogramme `flexway.kafka.tenant_budget.wait` (attente d'un tenant pour sa part d'octets en vol) : durées strictement croissantes et positives, 20 au plus ; défaut de 1 ms à 30 s. Lues une seule fois au démarrage."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "1.6.0"
            },
            "closures": {
              "default": true,
              "description": "Counts the normal closures of Kafka connections (`flexway.kafka.connections.closed`). Default `true`.",
              "type": "boolean",
              "x-flexway-description": {
                "en": "Counts the normal closures of Kafka connections (`flexway.kafka.connections.closed`). Default `true`.",
                "fr": "Compte les fermetures normales de connexions Kafka (`flexway.kafka.connections.closed`). Défaut `true`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "Measurements of the Kafka listener beyond its fixed instruments.",
            "fr": "Mesures de l'écouteur Kafka au-delà de ses instruments fixes."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        },
        "log_level": {
          "default": "info",
          "description": "Least severe level written to the logs: `debug`, `info` (default), `warn`, `error` or `fatal`. Changes without a restart, for instance `debug` for the time of a diagnosis.",
          "enum": [
            "debug",
            "info",
            "warn",
            "error",
            "fatal"
          ],
          "type": "string",
          "x-flexway-description": {
            "en": "Least severe level written to the logs: `debug`, `info` (default), `warn`, `error` or `fatal`. Changes without a restart, for instance `debug` for the time of a diagnosis.",
            "fr": "Niveau le moins grave écrit dans les journaux : `debug`, `info` (défaut), `warn`, `error` ou `fatal`. Se change à chaud, par exemple `debug` le temps d'un diagnostic."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.1.0"
        },
        "mqtt": {
          "additionalProperties": false,
          "description": "Measurements of the MQTT device listener beyond its fixed instruments.",
          "properties": {
            "closures": {
              "description": "Counts the normal closures of device connections (`flexway.mqtt.connections.closed`). Default `true`.",
              "type": "boolean",
              "x-flexway-description": {
                "en": "Counts the normal closures of device connections (`flexway.mqtt.connections.closed`). Default `true`.",
                "fr": "Compte les fermetures normales de connexions d'appareils (`flexway.mqtt.connections.closed`). Défaut `true`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.2.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "Measurements of the MQTT device listener beyond its fixed instruments.",
            "fr": "Mesures de l'écouteur MQTT des appareils au-delà de ses instruments fixes."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.2.0"
        },
        "otlp_endpoint": {
          "description": "OTLP collector of the traces (`host:port`, for instance `tempo.observ:4317`); takes precedence over `OTEL_EXPORTER_OTLP_ENDPOINT`. Empty: no trace export. Read once at start.",
          "type": "string",
          "x-flexway-description": {
            "en": "OTLP collector of the traces (`host:port`, for instance `tempo.observ:4317`); takes precedence over `OTEL_EXPORTER_OTLP_ENDPOINT`. Empty: no trace export. Read once at start.",
            "fr": "Collecteur OTLP des traces (`hôte:port`, par exemple `tempo.observ:4317`) ; prime sur `OTEL_EXPORTER_OTLP_ENDPOINT`. Vide : aucun export de traces. Lu une seule fois au démarrage."
          },
          "x-flexway-reloadable": false,
          "x-flexway-since": "0.2.0"
        },
        "sampling": {
          "additionalProperties": false,
          "description": "Trace sampling cap. Absent: every trace is kept. Read once at start.",
          "properties": {
            "max_per_second": {
              "description": "New root traces kept per second and per replica, a positive number; `0`: no cap.",
              "minimum": 0,
              "type": "number",
              "x-flexway-description": {
                "en": "New root traces kept per second and per replica, a positive number; `0`: no cap.",
                "fr": "Nouvelles traces racines gardées par seconde et par réplique, nombre positif ; `0` : sans plafond."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "1.0.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "Trace sampling cap. Absent: every trace is kept. Read once at start.",
            "fr": "Plafond d'échantillonnage des traces. Absent : toutes les traces sont gardées. Lu une seule fois au démarrage."
          },
          "x-flexway-reloadable": false,
          "x-flexway-since": "1.0.0"
        },
        "sparkplug": {
          "additionalProperties": false,
          "description": "The table of Sparkplug B edge nodes each replica keeps for the nodes that cross it (`GET /sparkplug/nodes`, the console's Devices screen). Reloadable.",
          "properties": {
            "max_devices_per_node": {
              "default": 1000,
              "description": "Devices (`DBIRTH`, `DDEATH`) kept for one node, 1 to 10000; past it the list is said truncated. Default 1000.",
              "type": "integer",
              "x-flexway-description": {
                "en": "Devices (`DBIRTH`, `DDEATH`) kept for one node, 1 to 10000; past it the list is said truncated. Default 1000.",
                "fr": "Appareils (`DBIRTH`, `DDEATH`) gardés pour un nœud, de 1 à 10000 ; au-delà, la liste est dite tronquée. Défaut 1000."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.2.0"
            },
            "max_nodes": {
              "default": 10000,
              "description": "Nodes and host applications kept per replica, 1 to 50000 (a node is a connection). Full, the table first forgets an unknown node, then the oldest offline one; full of online nodes, a new one is not kept and is counted. Default 10000.",
              "type": "integer",
              "x-flexway-description": {
                "en": "Nodes and host applications kept per replica, 1 to 50000 (a node is a connection). Full, the table first forgets an unknown node, then the oldest offline one; full of online nodes, a new one is not kept and is counted. Default 10000.",
                "fr": "Nœuds et applications hôtes gardés par réplique, de 1 à 50000 (un nœud est une connexion). Pleine, la table oublie d'abord un nœud inconnu, puis le plus ancien hors ligne ; pleine de nœuds en ligne, un nouveau n'est pas gardé et il est compté. Défaut 10000."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.2.0"
            },
            "max_nodes_per_tenant": {
              "default": 1000,
              "description": "Nodes of one tenant kept per replica, 1 to `max_nodes`: a tenant never fills the others' table; at its bound the table first forgets one of its unknown nodes, then its oldest offline one; full of online nodes, a new one is not kept and is counted. Default 1000 (or `max_nodes` when lower).",
              "type": "integer",
              "x-flexway-description": {
                "en": "Nodes of one tenant kept per replica, 1 to `max_nodes`: a tenant never fills the others' table; at its bound the table first forgets one of its unknown nodes, then its oldest offline one; full of online nodes, a new one is not kept and is counted. Default 1000 (or `max_nodes` when lower).",
                "fr": "Nœuds d'un même tenant gardés par réplique, de 1 à `max_nodes` : un tenant ne remplit jamais la table des autres ; à sa borne, la table oublie d'abord un de ses nœuds inconnus, puis le plus ancien hors ligne ; plein de nœuds en ligne, un nouveau n'est pas gardé et il est compté. Défaut 1000 (ou `max_nodes` s'il est plus bas)."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.2.0"
            },
            "offline_retention": {
              "default": "24h",
              "description": "How long a node offline, moved to another replica or seen only through its commands stays in the table, 1m to 720h. Default `24h`.",
              "not": {
                "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
              },
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "How long a node offline, moved to another replica or seen only through its commands stays in the table, 1m to 720h. Default `24h`.",
                "fr": "Durée pendant laquelle un nœud hors ligne, rattaché à une autre réplique ou seulement vu par ses commandes reste dans la table, de 1m à 720h. Défaut `24h`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.2.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "The table of Sparkplug B edge nodes each replica keeps for the nodes that cross it (`GET /sparkplug/nodes`, the console's Devices screen). Reloadable.",
            "fr": "Table des nœuds Sparkplug B que chaque réplique tient pour les nœuds qui la traversent (`GET /sparkplug/nodes`, écran Appareils de la console). Se change à chaud."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.2.0"
        }
      },
      "type": "object",
      "x-flexway-description": {
        "en": "The gateway's traces, logs and measurements. Without a collector the gateway still starts: a valid configuration, not a degraded one; `/metrics` stays served.",
        "fr": "Traces, journaux et mesures de la passerelle. Sans collecteur, la passerelle démarre quand même : c'est une configuration valide, pas un mode dégradé ; `/metrics` reste servi."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.2.0"
    },
    "policies": {
      "additionalProperties": false,
      "description": "The policy model: named, reusable definitions, attached by chains. Effective chain `global -> host -> routes -> operation`; the operation adds its own with `x-flexway-policies` in the contract.",
      "properties": {
        "chains": {
          "additionalProperties": false,
          "description": "Attaches policies, from the broadest to the most precise: global, per host, per route motif. A name prefixed with `!` removes a policy a broader level brought.",
          "properties": {
            "global": {
              "description": "Policies applied to every request, by definition name.",
              "items": {
                "type": "string"
              },
              "type": "array",
              "x-flexway-description": {
                "en": "Policies applied to every request, by definition name.",
                "fr": "Politiques appliquées à toute requête, par nom de définition."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.1.0"
            },
            "hosts": {
              "additionalProperties": {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "description": "Policies per host: host name -> list of definition names.",
              "type": "object",
              "x-flexway-description": {
                "en": "Policies per host: host name -> list of definition names.",
                "fr": "Politiques par hôte : nom d'hôte -> liste de noms de définitions."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.1.0"
            },
            "routes": {
              "additionalProperties": {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "description": "Policies per route motif: a path template starting with `/`, where `*` is one segment and `**` any number (`\"/orders/**\"`) -> list of definition names.",
              "type": "object",
              "x-flexway-description": {
                "en": "Policies per route motif: a path template starting with `/`, where `*` is one segment and `**` any number (`\"/orders/**\"`) -> list of definition names.",
                "fr": "Politiques par motif de route : un gabarit de chemin commençant par `/`, où `*` vaut un segment et `**` plusieurs (`\"/orders/**\"`) -> liste de noms de définitions."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.5.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "Attaches policies, from the broadest to the most precise: global, per host, per route motif. A name prefixed with `!` removes a policy a broader level brought.",
            "fr": "Attache les politiques, du plus large au plus précis : global, par hôte, par motif de route. Un nom préfixé de `!` retire une politique qu'un niveau plus large a apportée."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.1.0"
        },
        "definitions": {
          "additionalProperties": {
            "additionalProperties": false,
            "allOf": [
              {
                "if": {
                  "properties": {
                    "type": {
                      "const": "cache"
                    }
                  },
                  "required": [
                    "type"
                  ]
                },
                "then": {
                  "properties": {
                    "config": {
                      "$ref": "#/$defs/policy.cache"
                    }
                  }
                }
              },
              {
                "if": {
                  "properties": {
                    "type": {
                      "const": "cors"
                    }
                  },
                  "required": [
                    "type"
                  ]
                },
                "then": {
                  "properties": {
                    "config": {
                      "$ref": "#/$defs/policy.cors"
                    }
                  }
                }
              },
              {
                "if": {
                  "properties": {
                    "type": {
                      "const": "external-call"
                    }
                  },
                  "required": [
                    "type"
                  ]
                },
                "then": {
                  "properties": {
                    "config": {
                      "$ref": "#/$defs/policy.external-call"
                    }
                  }
                }
              },
              {
                "if": {
                  "properties": {
                    "type": {
                      "const": "header-inject"
                    }
                  },
                  "required": [
                    "type"
                  ]
                },
                "then": {
                  "properties": {
                    "config": {
                      "$ref": "#/$defs/policy.header-inject"
                    }
                  }
                }
              },
              {
                "if": {
                  "properties": {
                    "type": {
                      "const": "header-remove"
                    }
                  },
                  "required": [
                    "type"
                  ]
                },
                "then": {
                  "properties": {
                    "config": {
                      "$ref": "#/$defs/policy.header-remove"
                    }
                  }
                }
              },
              {
                "if": {
                  "properties": {
                    "type": {
                      "const": "map-status"
                    }
                  },
                  "required": [
                    "type"
                  ]
                },
                "then": {
                  "properties": {
                    "config": {
                      "$ref": "#/$defs/policy.map-status"
                    }
                  }
                }
              },
              {
                "if": {
                  "properties": {
                    "type": {
                      "const": "query-inject"
                    }
                  },
                  "required": [
                    "type"
                  ]
                },
                "then": {
                  "properties": {
                    "config": {
                      "$ref": "#/$defs/policy.query-inject"
                    }
                  }
                }
              },
              {
                "if": {
                  "properties": {
                    "type": {
                      "const": "query-remove"
                    }
                  },
                  "required": [
                    "type"
                  ]
                },
                "then": {
                  "properties": {
                    "config": {
                      "$ref": "#/$defs/policy.query-remove"
                    }
                  }
                }
              },
              {
                "if": {
                  "properties": {
                    "type": {
                      "const": "quota"
                    }
                  },
                  "required": [
                    "type"
                  ]
                },
                "then": {
                  "properties": {
                    "config": {
                      "$ref": "#/$defs/policy.quota"
                    }
                  }
                }
              },
              {
                "if": {
                  "properties": {
                    "type": {
                      "const": "rate-limit"
                    }
                  },
                  "required": [
                    "type"
                  ]
                },
                "then": {
                  "properties": {
                    "config": {
                      "$ref": "#/$defs/policy.rate-limit"
                    }
                  }
                }
              },
              {
                "if": {
                  "properties": {
                    "type": {
                      "const": "redact"
                    }
                  },
                  "required": [
                    "type"
                  ]
                },
                "then": {
                  "properties": {
                    "config": {
                      "$ref": "#/$defs/policy.redact"
                    }
                  }
                }
              },
              {
                "if": {
                  "properties": {
                    "type": {
                      "const": "rewrite-path"
                    }
                  },
                  "required": [
                    "type"
                  ]
                },
                "then": {
                  "properties": {
                    "config": {
                      "$ref": "#/$defs/policy.rewrite-path"
                    }
                  }
                }
              },
              {
                "if": {
                  "properties": {
                    "type": {
                      "const": "transform-body"
                    }
                  },
                  "required": [
                    "type"
                  ]
                },
                "then": {
                  "properties": {
                    "config": {
                      "$ref": "#/$defs/policy.transform-body"
                    }
                  }
                }
              }
            ],
            "properties": {
              "config": {
                "description": "The type's own configuration, decoded strictly against that type's schema (see the policy types): an unknown key is refused.",
                "x-flexway-description": {
                  "en": "The type's own configuration, decoded strictly against that type's schema (see the policy types): an unknown key is refused.",
                  "fr": "Configuration propre au type, décodée strictement contre le schéma de ce type (voir les types de politiques) : une clé inconnue est refusée."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.1.0"
              },
              "phase": {
                "description": "When the policy acts: `request`, `response` or `error`, among the phases its type accepts. Absent: the type's first phase.",
                "enum": [
                  "request",
                  "response",
                  "error"
                ],
                "type": "string",
                "x-flexway-description": {
                  "en": "When the policy acts: `request`, `response` or `error`, among the phases its type accepts. Absent: the type's first phase.",
                  "fr": "Moment où la politique agit : `request`, `response` ou `error`, parmi les phases que son type accepte. Absente : la première phase du type."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.5.0"
              },
              "type": {
                "description": "The policy's type, from the catalogue: `cors`, `rate-limit`, `quota`, `cache`, `header-inject`, `header-remove`, `rewrite-path`, `query-inject`, `query-remove`, `transform-body`, `redact`, `map-status`, `external-call`. Required.",
                "enum": [
                  "cache",
                  "cors",
                  "external-call",
                  "header-inject",
                  "header-remove",
                  "map-status",
                  "query-inject",
                  "query-remove",
                  "quota",
                  "rate-limit",
                  "redact",
                  "rewrite-path",
                  "transform-body"
                ],
                "type": "string",
                "x-flexway-description": {
                  "en": "The policy's type, from the catalogue: `cors`, `rate-limit`, `quota`, `cache`, `header-inject`, `header-remove`, `rewrite-path`, `query-inject`, `query-remove`, `transform-body`, `redact`, `map-status`, `external-call`. Required.",
                  "fr": "Type de la politique, dans le catalogue : `cors`, `rate-limit`, `quota`, `cache`, `header-inject`, `header-remove`, `rewrite-path`, `query-inject`, `query-remove`, `transform-body`, `redact`, `map-status`, `external-call`. Obligatoire."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.1.0"
              },
              "when": {
                "description": "CEL condition compiled at load (`has(auth.subject)`): the policy applies only when it holds. Refused for `cors`, `rate-limit` and `quota`, which are attached where they apply instead.",
                "type": "string",
                "x-flexway-description": {
                  "en": "CEL condition compiled at load (`has(auth.subject)`): the policy applies only when it holds. Refused for `cors`, `rate-limit` and `quota`, which are attached where they apply instead.",
                  "fr": "Condition CEL compilée au chargement (`has(auth.subject)`) : la politique ne s'applique que si elle est vraie. Refusée pour `cors`, `rate-limit` et `quota`, qu'on attache plutôt là où ils s'appliquent."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.5.0"
              }
            },
            "required": [
              "type"
            ],
            "type": "object"
          },
          "description": "The named policies: name -> definition (`type`, `phase`, `when`, `config`). Only the policies a chain or `x-flexway-policies` attaches apply.",
          "type": "object",
          "x-flexway-description": {
            "en": "The named policies: name -> definition (`type`, `phase`, `when`, `config`). Only the policies a chain or `x-flexway-policies` attaches apply.",
            "fr": "Les politiques nommées : nom -> définition (`type`, `phase`, `when`, `config`). Seules les politiques attachées par une chaîne ou par `x-flexway-policies` s'appliquent."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.1.0"
        },
        "fragments": {
          "additionalProperties": {
            "additionalProperties": false,
            "properties": {
              "digest": {
                "description": "The digest that pins the file: `sha256:` followed by the 64 hex characters of the `sha256` of its bytes, with no canonical form - what `sha256sum` and `flexway fragment digest` print. Required. Different from the digest read: refused, naming the import, the expected and the read digest.",
                "pattern": "^sha256:[0-9a-f]{64}$",
                "type": "string",
                "x-flexway-description": {
                  "en": "The digest that pins the file: `sha256:` followed by the 64 hex characters of the `sha256` of its bytes, with no canonical form - what `sha256sum` and `flexway fragment digest` print. Required. Different from the digest read: refused, naming the import, the expected and the read digest.",
                  "fr": "Empreinte qui épingle le fichier : `sha256:` suivi des 64 caractères hexadécimaux du `sha256` de ses octets, sans forme canonique - la valeur de `sha256sum` et de `flexway fragment digest`. Obligatoire. Différente de l'empreinte lue : refus qui nomme l'import, l'attendue et la lue."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.7.0"
              },
              "path": {
                "description": "The fragment file (`kind: PolicyFragment`), relative to `flexway.yaml`, in its directory or below (`..` and an absolute path outside that directory refused); a regular file of 1 MiB at most. Required. Read again at every reload: a file missing, or changed without its digest, refuses the load, and the configuration in force keeps serving.",
                "type": "string",
                "x-flexway-description": {
                  "en": "The fragment file (`kind: PolicyFragment`), relative to `flexway.yaml`, in its directory or below (`..` and an absolute path outside that directory refused); a regular file of 1 MiB at most. Required. Read again at every reload: a file missing, or changed without its digest, refuses the load, and the configuration in force keeps serving.",
                  "fr": "Fichier du fragment (`kind: PolicyFragment`), relatif au `flexway.yaml`, dans son répertoire ou en dessous (`..` et chemin absolu hors de ce répertoire refusés) ; un fichier ordinaire de 1 Mio au plus. Obligatoire. Relu à chaque rechargement : un fichier absent ou changé sans son empreinte refuse le chargement, et la configuration en cours reste."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.7.0"
              },
              "verify": {
                "additionalProperties": false,
                "description": "Reserved for verifying a signature of the fragment, which is not built in this version: declared, it refuses the load rather than being ignored. The digest alone pins the file.",
                "properties": {
                  "bundle": {
                    "description": "Reserved: the fragment's signature bundle. Not built in this version - refused at load.",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "Reserved: the fragment's signature bundle. Not built in this version - refused at load.",
                      "fr": "Réservé : le paquet de signature du fragment. Non construit dans cette version - refusé au chargement."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "1.7.0"
                  },
                  "key": {
                    "description": "Reserved: the public key that verifies the signature. Not built in this version - refused at load.",
                    "type": "string",
                    "x-flexway-description": {
                      "en": "Reserved: the public key that verifies the signature. Not built in this version - refused at load.",
                      "fr": "Réservé : la clé publique qui vérifie la signature. Non construit dans cette version - refusé au chargement."
                    },
                    "x-flexway-reloadable": true,
                    "x-flexway-since": "1.7.0"
                  }
                },
                "type": "object",
                "x-flexway-description": {
                  "en": "Reserved for verifying a signature of the fragment, which is not built in this version: declared, it refuses the load rather than being ignored. The digest alone pins the file.",
                  "fr": "Réservé à la vérification d'une signature du fragment, qui n'est pas construite dans cette version : déclarée, elle refuse le chargement plutôt que d'être ignorée. L'empreinte seule épingle le fichier."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.7.0"
              }
            },
            "required": [
              "digest",
              "path"
            ],
            "type": "object"
          },
          "description": "Imported policy fragments (1.7.0): import name -> file pinned by its digest. A fragment's definitions are named `<import>/<name>` here; the ones it enforces run at the head of every chain of the HTTP listener, before `global`, and are neither removed, replaced nor undone locally. Read from mounted files only, never from the network; YAML anchors, aliases and merge keys refused here. Absent: no fragment, the behaviour of 1.6.0. The import name: lower-case letters, digits and `-`, 63 at most.",
          "type": "object",
          "x-flexway-description": {
            "en": "Imported policy fragments (1.7.0): import name -> file pinned by its digest. A fragment's definitions are named `<import>/<name>` here; the ones it enforces run at the head of every chain of the HTTP listener, before `global`, and are neither removed, replaced nor undone locally. Read from mounted files only, never from the network; YAML anchors, aliases and merge keys refused here. Absent: no fragment, the behaviour of 1.6.0. The import name: lower-case letters, digits and `-`, 63 at most.",
            "fr": "Fragments de politique importés (1.7.0) : nom d'import -> fichier épinglé par son empreinte. Les définitions d'un fragment s'appellent ici `<import>/<nom>` ; celles qu'il impose passent en tête de chaque chaîne de l'écouteur HTTP, avant `global`, et ne se retirent, ne se remplacent ni ne se défont localement. Lu de fichiers montés seulement, jamais du réseau ; ancres, alias et clés de fusion YAML refusés ici. Absent : aucun fragment, comportement de 1.6.0. Le nom d'import : lettres minuscules, chiffres et `-`, 63 au plus."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.7.0"
        }
      },
      "type": "object",
      "x-flexway-description": {
        "en": "The policy model: named, reusable definitions, attached by chains. Effective chain `global -> host -> routes -> operation`; the operation adds its own with `x-flexway-policies` in the contract.",
        "fr": "Le modèle de politiques : des définitions nommées et réutilisables, attachées par des chaînes. Chaîne effective `global -> hôte -> routes -> opération` ; l'opération ajoute la sienne par `x-flexway-policies` au contrat."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.1.0"
    },
    "schema_registry": {
      "additionalProperties": false,
      "description": "The schema registry binary payloads are read under: the Confluent API, served by Confluent, Apicurio, Karapace and Redpanda. Read, never written. Absent: a message that declares the registry's wire format is refused at load.",
      "properties": {
        "auth": {
          "additionalProperties": false,
          "description": "How the gateway authenticates to the registry: `username` and `password` (HTTP Basic, Confluent Cloud's key and secret), or `token` - not both. Refused when `url` is `http://`.",
          "properties": {
            "password": {
              "description": "Password by reference, `${VAR}` or `file:/path`, read at each request; goes with `username`.",
              "pattern": "^(\\$\\{[A-Za-z_][A-Za-z0-9_]*\\}|file:/\\S+)$",
              "type": "string",
              "x-flexway-description": {
                "en": "Password by reference, `${VAR}` or `file:/path`, read at each request; goes with `username`.",
                "fr": "Mot de passe par référence, `${VAR}` ou `file:/chemin`, relu à chaque requête ; va avec `username`."
              },
              "x-flexway-reference": true,
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "token": {
              "description": "Bearer token by reference, `${VAR}` or `file:/path`; exclusive with `username` and `password`.",
              "pattern": "^(\\$\\{[A-Za-z_][A-Za-z0-9_]*\\}|file:/\\S+)$",
              "type": "string",
              "x-flexway-description": {
                "en": "Bearer token by reference, `${VAR}` or `file:/path`; exclusive with `username` and `password`.",
                "fr": "Jeton porteur par référence, `${VAR}` ou `file:/chemin` ; exclusif de `username` et `password`."
              },
              "x-flexway-reference": true,
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "username": {
              "description": "HTTP Basic user name; goes with `password`.",
              "type": "string",
              "x-flexway-description": {
                "en": "HTTP Basic user name; goes with `password`.",
                "fr": "Nom d'utilisateur HTTP Basic ; va avec `password`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "How the gateway authenticates to the registry: `username` and `password` (HTTP Basic, Confluent Cloud's key and secret), or `token` - not both. Refused when `url` is `http://`.",
            "fr": "Authentification de la passerelle au registre : `username` et `password` (HTTP Basic, la clé et le secret de Confluent Cloud), ou `token` - pas les deux. Refusée si `url` est en `http://`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        },
        "circuit_breaker": {
          "additionalProperties": false,
          "description": "The registry's circuit breaker, as an upstream's: open, a message that needs the registry is refused at once (`503`), never waited for. On by default.",
          "properties": {
            "cooldown": {
              "default": "5s",
              "description": "How long the open breaker rests before a trial call; default `5s`.",
              "not": {
                "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
              },
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "How long the open breaker rests before a trial call; default `5s`.",
                "fr": "Repos du coupe-circuit ouvert avant un appel d'essai ; défaut `5s`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "failure_ratio": {
              "default": 0.5,
              "description": "Share of failures that opens the breaker, in (0, 1]; default `0.5`.",
              "maximum": 1,
              "minimum": 0,
              "type": "number",
              "x-flexway-description": {
                "en": "Share of failures that opens the breaker, in (0, 1]; default `0.5`.",
                "fr": "Part d'échecs qui ouvre le coupe-circuit, dans (0, 1] ; défaut `0.5`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "min_requests": {
              "default": 20,
              "description": "Minimum calls in the window before the failure share counts; default `20`.",
              "type": "integer",
              "x-flexway-description": {
                "en": "Minimum calls in the window before the failure share counts; default `20`.",
                "fr": "Appels minimum dans la fenêtre avant que la part d'échecs compte ; défaut `20`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "window": {
              "default": "10s",
              "description": "Sliding window over which the failure share is measured; default `10s`.",
              "not": {
                "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
              },
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "Sliding window over which the failure share is measured; default `10s`.",
                "fr": "Fenêtre glissante sur laquelle la part d'échecs est mesurée ; défaut `10s`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "The registry's circuit breaker, as an upstream's: open, a message that needs the registry is refused at once (`503`), never waited for. On by default.",
            "fr": "Coupe-circuit du registre, comme celui d'un amont : ouvert, un message qui a besoin du registre est refusé aussitôt (`503`), jamais attendu. Actif par défaut."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        },
        "max_schemas": {
          "default": 1000,
          "description": "Schemas kept in memory, by id, compiled once each; from 1 to 100000, default `1000`.",
          "maximum": 100000,
          "minimum": 1,
          "type": "integer",
          "x-flexway-description": {
            "en": "Schemas kept in memory, by id, compiled once each; from 1 to 100000, default `1000`.",
            "fr": "Schémas gardés en mémoire, par identifiant, compilés une fois chacun ; de 1 à 100000, défaut `1000`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        },
        "timeout": {
          "default": "2s",
          "description": "Timeout of a registry lookup, which holds the message that needs it; more than 0 and `30s` at most, default `2s`.",
          "not": {
            "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
          },
          "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
          "type": "string",
          "x-flexway-description": {
            "en": "Timeout of a registry lookup, which holds the message that needs it; more than 0 and `30s` at most, default `2s`.",
            "fr": "Délai d'une recherche au registre, qui retient le message qui en a besoin ; plus de 0 et `30s` au plus, défaut `2s`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        },
        "tls": {
          "additionalProperties": false,
          "description": "Client TLS toward the registry; only with an `https://` `url`.",
          "properties": {
            "ca_file": {
              "description": "PEM file of the authority that verifies the server's certificate; absent: the system's authorities. The file must exist.",
              "type": "string",
              "x-flexway-description": {
                "en": "PEM file of the authority that verifies the server's certificate; absent: the system's authorities. The file must exist.",
                "fr": "Fichier PEM de l'autorité qui vérifie le certificat du serveur ; absent : les autorités du système. Le fichier doit exister."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "cert_file": {
              "description": "Client certificate (PEM) presented to the registry; goes with `key_file`. The file must exist.",
              "type": "string",
              "x-flexway-description": {
                "en": "Client certificate (PEM) presented to the registry; goes with `key_file`. The file must exist.",
                "fr": "Certificat client PEM présenté au registre ; va avec `key_file`. Le fichier doit exister."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "key_file": {
              "description": "Private key (PEM) of the client certificate; goes with `cert_file`. The file must exist.",
              "type": "string",
              "x-flexway-description": {
                "en": "Private key (PEM) of the client certificate; goes with `cert_file`. The file must exist.",
                "fr": "Clé privée PEM du certificat client ; va avec `cert_file`. Le fichier doit exister."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            },
            "server_name": {
              "description": "Name expected in the registry's certificate, when it differs from the host of `url`.",
              "type": "string",
              "x-flexway-description": {
                "en": "Name expected in the registry's certificate, when it differs from the host of `url`.",
                "fr": "Nom attendu dans le certificat du registre, quand il diffère de l'hôte de `url`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.6.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "Client TLS toward the registry; only with an `https://` `url`.",
            "fr": "TLS client vers le registre ; seulement avec une `url` en `https://`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        },
        "url": {
          "description": "The registry's absolute `http(s)://` base address, without credentials, query nor fragment (`https://registry.internal:8081`); required. With `http://`, neither `tls` nor `auth`.",
          "type": "string",
          "x-flexway-description": {
            "en": "The registry's absolute `http(s)://` base address, without credentials, query nor fragment (`https://registry.internal:8081`); required. With `http://`, neither `tls` nor `auth`.",
            "fr": "Adresse de base absolue du registre en `http(s)://`, sans identifiants, paramètres ni fragment (`https://registry.internal:8081`) ; obligatoire. En `http://`, ni `tls` ni `auth`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.6.0"
        }
      },
      "required": [
        "url"
      ],
      "type": "object",
      "x-flexway-description": {
        "en": "The schema registry binary payloads are read under: the Confluent API, served by Confluent, Apicurio, Karapace and Redpanda. Read, never written. Absent: a message that declares the registry's wire format is refused at load.",
        "fr": "Le registre de schémas sous lequel sont lues les charges binaires : l'API de Confluent, que servent Confluent, Apicurio, Karapace et Redpanda. Lu, jamais écrit. Absent : un message qui déclare le format filaire du registre est refusé au chargement."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "1.6.0"
    },
    "server": {
      "additionalProperties": false,
      "description": "How the gateway behaves toward its upstreams and during a shutdown, independently of any operation. Every key has a default: an empty `server:` section is valid.",
      "properties": {
        "body": {
          "additionalProperties": false,
          "description": "Bounds of the response bodies the body policies read (`transform-body`, `redact`, `map-status`), for the operations that declare one only.",
          "properties": {
            "max_bytes": {
              "anyOf": [
                {
                  "minimum": 1,
                  "type": "integer"
                },
                {
                  "pattern": "^\\s*[1-9][0-9]*\\s*(B|KiB|MiB|GiB)?\\s*$",
                  "type": "string"
                }
              ],
              "default": "1MiB",
              "description": "Largest response body read to be transformed, a size (`1MiB`, `512KiB` or a number of bytes); default `1MiB`. Past it: `502 response_too_large`, never a truncated nor an untransformed body.",
              "x-flexway-description": {
                "en": "Largest response body read to be transformed, a size (`1MiB`, `512KiB` or a number of bytes); default `1MiB`. Past it: `502 response_too_large`, never a truncated nor an untransformed body.",
                "fr": "Plus grand corps de réponse lu pour être transformé, taille (`1MiB`, `512KiB` ou un nombre d'octets) ; défaut `1MiB`. Au-delà : `502 response_too_large`, jamais un corps tronqué ni non transformé."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.2.0"
            },
            "validate_sample": {
              "default": 0.01,
              "description": "Share of transformed responses checked against the contract's schema, between `0` and `1`; default `0.01`. A departure is counted and logged, never answered as an error; `0` checks none.",
              "maximum": 1,
              "minimum": 0,
              "type": "number",
              "x-flexway-description": {
                "en": "Share of transformed responses checked against the contract's schema, between `0` and `1`; default `0.01`. A departure is counted and logged, never answered as an error; `0` checks none.",
                "fr": "Part des réponses transformées vérifiées contre le schéma du contrat, entre `0` et `1` ; défaut `0.01`. Un écart est compté et journalisé, jamais servi en erreur ; `0` n'en vérifie aucune."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "1.2.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "Bounds of the response bodies the body policies read (`transform-body`, `redact`, `map-status`), for the operations that declare one only.",
            "fr": "Bornes des corps de réponse que lisent les politiques de corps (`transform-body`, `redact`, `map-status`), pour les seules opérations qui en déclarent."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.2.0"
        },
        "cache": {
          "additionalProperties": false,
          "description": "Bounds of the response cache of the operations that declare one. Holds nothing while no operation declares a cache. Read once at start.",
          "properties": {
            "max_bytes": {
              "anyOf": [
                {
                  "minimum": 1,
                  "type": "integer"
                },
                {
                  "pattern": "^\\s*[1-9][0-9]*\\s*(B|KiB|MiB|GiB)?\\s*$",
                  "type": "string"
                }
              ],
              "default": "32MiB",
              "description": "Total memory of the cache per replica, a size; default `32MiB`. Past it, the least recently used response is evicted.",
              "x-flexway-description": {
                "en": "Total memory of the cache per replica, a size; default `32MiB`. Past it, the least recently used response is evicted.",
                "fr": "Mémoire totale du cache par réplique, taille ; défaut `32MiB`. Au-delà, la réponse la moins récemment servie est évincée."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "1.2.0"
            },
            "max_entry_bytes": {
              "anyOf": [
                {
                  "minimum": 1,
                  "type": "integer"
                },
                {
                  "pattern": "^\\s*[1-9][0-9]*\\s*(B|KiB|MiB|GiB)?\\s*$",
                  "type": "string"
                }
              ],
              "default": "1MiB",
              "description": "Largest response stored, a size; default `1MiB` (at most `max_bytes`). A larger one is relayed, never kept.",
              "x-flexway-description": {
                "en": "Largest response stored, a size; default `1MiB` (at most `max_bytes`). A larger one is relayed, never kept.",
                "fr": "Plus grande réponse gardée, taille ; défaut `1MiB` (au plus `max_bytes`). Une réponse plus grande est relayée, jamais gardée."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "1.2.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "Bounds of the response cache of the operations that declare one. Holds nothing while no operation declares a cache. Read once at start.",
            "fr": "Bornes du cache de réponses des opérations qui en déclarent un. Ne tient rien tant qu'aucune opération ne déclare de cache. Lu une seule fois au démarrage."
          },
          "x-flexway-reloadable": false,
          "x-flexway-since": "1.2.0"
        },
        "counters": {
          "additionalProperties": false,
          "description": "Shares rate limits and quotas across replicas through a Redis-compatible shared cache (Redis, Dragonfly or Valkey), reconciled periodically. Absent: every counter is local to its replica, and no quota can be declared. Read once at start.",
          "properties": {
            "prefix": {
              "default": "flexway",
              "description": "Prefix of this deployment's keys in the shared cache: letters, digits and dashes; default `flexway`. Two deployments sharing a cache would otherwise count together.",
              "type": "string",
              "x-flexway-description": {
                "en": "Prefix of this deployment's keys in the shared cache: letters, digits and dashes; default `flexway`. Two deployments sharing a cache would otherwise count together.",
                "fr": "Préfixe des clés de ce déploiement dans le cache partagé : lettres, chiffres et tirets ; défaut `flexway`. Deux déploiements qui partagent un cache compteraient sinon ensemble."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "1.0.0"
            },
            "store": {
              "description": "Address of the shared cache: `redis://host:port` or `rediss://`, without a password, or a reference (`${VAR}`, `file:/path`) when it carries one. Required.",
              "type": "string",
              "x-flexway-description": {
                "en": "Address of the shared cache: `redis://host:port` or `rediss://`, without a password, or a reference (`${VAR}`, `file:/path`) when it carries one. Required.",
                "fr": "Adresse du cache partagé : `redis://hôte:port` ou `rediss://`, sans mot de passe, ou une référence (`${VAR}`, `file:/chemin`) quand elle en porte un. Obligatoire."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "1.0.0"
            },
            "sync": {
              "default": "1s",
              "description": "Reconciliation period with the shared cache, between `100ms` and `1m`; default `1s`. It is the window by which a shared limit may be exceeded.",
              "not": {
                "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
              },
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "Reconciliation period with the shared cache, between `100ms` and `1m`; default `1s`. It is the window by which a shared limit may be exceeded.",
                "fr": "Période de réconciliation avec le cache partagé, entre `100ms` et `1m` ; défaut `1s`. C'est la fenêtre dont une limite partagée peut être dépassée."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "1.0.0"
            }
          },
          "required": [
            "store"
          ],
          "type": "object",
          "x-flexway-description": {
            "en": "Shares rate limits and quotas across replicas through a Redis-compatible shared cache (Redis, Dragonfly or Valkey), reconciled periodically. Absent: every counter is local to its replica, and no quota can be declared. Read once at start.",
            "fr": "Partage des débits et des quotas entre répliques par un cache partagé compatible Redis (Redis, Dragonfly ou Valkey), avec réconciliation périodique. Absent : chaque compteur est local à sa réplique, et aucun quota ne peut être déclaré. Lu une seule fois au démarrage."
          },
          "x-flexway-reloadable": false,
          "x-flexway-since": "1.0.0"
        },
        "in_flight": {
          "additionalProperties": false,
          "description": "Gate in front of the data plane: requests worked on at once, waiting for a slot, open connections; past it, `503` at once. Absent: derived from the container's memory limit when it has one. Read once at start.",
          "properties": {
            "connections": {
              "description": "Client connections open at once, per listener; past it, a new one waits in the kernel's accept queue. `0`: no limit. Absent: derived from the memory limit (25 % of memory / 32 KiB).",
              "minimum": 0,
              "type": "integer",
              "x-flexway-description": {
                "en": "Client connections open at once, per listener; past it, a new one waits in the kernel's accept queue. `0`: no limit. Absent: derived from the memory limit (25 % of memory / 32 KiB).",
                "fr": "Connexions clientes ouvertes à la fois, par écouteur ; au-delà, une nouvelle attend dans la file du noyau. `0` : sans plafond. Absente : dérivée de la limite mémoire (25 % de la mémoire / 32 KiB)."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "1.1.0"
            },
            "max": {
              "description": "Requests in flight at once, streams included. `0`: no limit. Absent: derived from the memory limit (50 % of memory / 128 KiB, at least 64), adapted to saturation.",
              "minimum": 0,
              "type": "integer",
              "x-flexway-description": {
                "en": "Requests in flight at once, streams included. `0`: no limit. Absent: derived from the memory limit (50 % of memory / 128 KiB, at least 64), adapted to saturation.",
                "fr": "Requêtes en vol à la fois, flux compris. `0` : sans plafond. Absente : dérivée de la limite mémoire (50 % de la mémoire / 128 KiB, 64 au moins), adaptée à la saturation."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "1.1.0"
            },
            "queue": {
              "description": "Requests that may wait for a slot; default `0` (refused at once). Requires `wait`, and a non-zero `max`.",
              "minimum": 0,
              "type": "integer",
              "x-flexway-description": {
                "en": "Requests that may wait for a slot; default `0` (refused at once). Requires `wait`, and a non-zero `max`.",
                "fr": "Requêtes qui peuvent attendre une place ; défaut `0` (refus immédiat). Exige `wait`, et une limite `max` non nulle."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "1.1.0"
            },
            "wait": {
              "description": "How long a queued request waits at most, `10s` at most. Required with `queue`, refused without it.",
              "not": {
                "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
              },
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "How long a queued request waits at most, `10s` at most. Required with `queue`, refused without it.",
                "fr": "Attente au plus d'une requête en file, `10s` au plus. Exigée avec `queue`, refusée sans elle."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "1.1.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "Gate in front of the data plane: requests worked on at once, waiting for a slot, open connections; past it, `503` at once. Absent: derived from the container's memory limit when it has one. Read once at start.",
            "fr": "Porte devant le plan de données : requêtes traitées à la fois, attente d'une place, connexions ouvertes ; au-delà, `503` aussitôt. Absente : dérivée de la limite mémoire du conteneur quand il en a une. Lue une seule fois au démarrage."
          },
          "x-flexway-reloadable": false,
          "x-flexway-since": "1.1.0"
        },
        "limits": {
          "additionalProperties": false,
          "description": "What one request may make the gateway hold.",
          "properties": {
            "max_body": {
              "anyOf": [
                {
                  "minimum": 1,
                  "type": "integer"
                },
                {
                  "pattern": "^\\s*[1-9][0-9]*\\s*(B|KiB|MiB|GiB)?\\s*$",
                  "type": "string"
                }
              ],
              "default": "1MiB",
              "description": "Largest request body read - it is read only to be validated against the contract; a size, default `1MiB`. Past it: `413`. A body that is only relayed is never held, whatever its size.",
              "x-flexway-description": {
                "en": "Largest request body read - it is read only to be validated against the contract; a size, default `1MiB`. Past it: `413`. A body that is only relayed is never held, whatever its size.",
                "fr": "Plus grand corps de requête lu - il n'est lu que pour être validé contre le contrat ; taille, défaut `1MiB`. Au-delà : `413`. Un corps seulement relayé n'est jamais retenu, quelle que soit sa taille."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.4.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "What one request may make the gateway hold.",
            "fr": "Ce qu'une requête peut faire tenir à la passerelle."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.4.0"
        },
        "peer_identity_header": {
          "description": "Header a local mesh proxy writes the peer's verified identity into (Linkerd: `l5d-client-id`), believed from peers of `trusted_proxies` only (required with it). Declares a mesh; incompatible with `auth.trusted_headers`.",
          "type": "string",
          "x-flexway-description": {
            "en": "Header a local mesh proxy writes the peer's verified identity into (Linkerd: `l5d-client-id`), believed from peers of `trusted_proxies` only (required with it). Declares a mesh; incompatible with `auth.trusted_headers`.",
            "fr": "En-tête où un proxy de maillage local écrit l'identité vérifiée du pair (Linkerd : `l5d-client-id`), crue des seuls pairs de `trusted_proxies` (obligatoire avec lui). Déclare un maillage ; incompatible avec `auth.trusted_headers`."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "1.0.0"
        },
        "reload": {
          "additionalProperties": false,
          "description": "How the gateway notices a changed configuration. Read once at start.",
          "properties": {
            "interval": {
              "default": "5s",
              "description": "How often the configuration and its contracts are read again and compared by content; default `5s`. `\"0s\"`: never, `SIGHUP` alone reloads.",
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "How often the configuration and its contracts are read again and compared by content; default `5s`. `\"0s\"`: never, `SIGHUP` alone reloads.",
                "fr": "Intervalle de relecture de la configuration et de ses contrats, comparés par contenu ; défaut `5s`. `\"0s\"` : jamais, seul `SIGHUP` recharge."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "0.6.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "How the gateway notices a changed configuration. Read once at start.",
            "fr": "Comment la passerelle voit une configuration changée. Lu une seule fois au démarrage."
          },
          "x-flexway-reloadable": false,
          "x-flexway-since": "0.6.0"
        },
        "shedding": {
          "additionalProperties": false,
          "description": "Sheds a share of the traffic while the gateway itself is saturated. Absent: nothing is shed. Read once at start.",
          "properties": {
            "target": {
              "description": "Saturation above which the gateway sheds: the 99th percentile of the Go scheduler's latency (how long a runnable goroutine waits for a processor), between `1ms` and `1s`. Operations marked `x-flexway-priority: critical` are never shed.",
              "not": {
                "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
              },
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "Saturation above which the gateway sheds: the 99th percentile of the Go scheduler's latency (how long a runnable goroutine waits for a processor), between `1ms` and `1s`. Operations marked `x-flexway-priority: critical` are never shed.",
                "fr": "Saturation au-delà de laquelle la passerelle déleste : 99e centile de la latence d'ordonnancement Go (attente d'un processeur par une goroutine prête), entre `1ms` et `1s`. Les opérations `x-flexway-priority: critical` ne sont jamais délestées."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "1.0.0"
            }
          },
          "required": [
            "target"
          ],
          "type": "object",
          "x-flexway-description": {
            "en": "Sheds a share of the traffic while the gateway itself is saturated. Absent: nothing is shed. Read once at start.",
            "fr": "Délestage d'une part du trafic pendant que la passerelle elle-même sature. Absent : rien n'est délesté. Lu une seule fois au démarrage."
          },
          "x-flexway-reloadable": false,
          "x-flexway-since": "1.0.0"
        },
        "shutdown": {
          "additionalProperties": false,
          "description": "What happens between `SIGTERM` and exit. Read once at start.",
          "properties": {
            "drain": {
              "default": "20s",
              "description": "Time in-flight requests and streams get to finish once new ones are refused; default `20s`. Past it, the remaining connections are closed, and that is logged.",
              "not": {
                "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
              },
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "Time in-flight requests and streams get to finish once new ones are refused; default `20s`. Past it, the remaining connections are closed, and that is logged.",
                "fr": "Temps laissé aux requêtes et flux en cours pour finir une fois les nouvelles refusées ; défaut `20s`. Au-delà, les connexions restantes sont fermées et c'est journalisé."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "0.2.0"
            },
            "mqtt_drain_spread": {
              "default": "30s",
              "description": "Spreads the redirections of the MQTT listener's devices over the drain, no reconnection storm on the other replicas; capped at half of `drain`. From `0s` to `10m`, default `30s`.",
              "not": {
                "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
              },
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "Spreads the redirections of the MQTT listener's devices over the drain, no reconnection storm on the other replicas; capped at half of `drain`. From `0s` to `10m`, default `30s`.",
                "fr": "Étale les redirections des appareils de l'écouteur MQTT sur l'arrêt, sans tempête de reconnexions sur les autres répliques ; plafonné à la moitié de `drain`. De `0s` à `10m`, défaut `30s`."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "0.2.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "What happens between `SIGTERM` and exit. Read once at start.",
            "fr": "Ce qui se passe entre `SIGTERM` et la sortie. Lu une seule fois au démarrage."
          },
          "x-flexway-reloadable": false,
          "x-flexway-since": "0.2.0"
        },
        "timeouts": {
          "additionalProperties": false,
          "description": "Budgets of one relayed exchange, in layers. There is deliberately no single global timeout.",
          "properties": {
            "connect": {
              "default": "5s",
              "description": "Time to establish a connection to an upstream, TLS handshake included. A duration (`5s`, `500ms`); default `5s`.",
              "not": {
                "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
              },
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "Time to establish a connection to an upstream, TLS handshake included. A duration (`5s`, `500ms`); default `5s`.",
                "fr": "Délai d'établissement d'une connexion vers un amont, poignée de main TLS comprise. Durée (`5s`, `500ms`) ; défaut `5s`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.2.0"
            },
            "read": {
              "default": "1m",
              "description": "Silence tolerated between two bytes of an upstream response; it alone governs a stream. Default `60s`.",
              "not": {
                "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
              },
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "Silence tolerated between two bytes of an upstream response; it alone governs a stream. Default `60s`.",
                "fr": "Silence toléré entre deux octets d'une réponse amont ; c'est lui seul qui gouverne un flux. Défaut `60s`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.2.0"
            },
            "total": {
              "default": "30s",
              "description": "Budget of the whole exchange, retries included; a streamed response is exempt from it. Default `30s`. Overridden by `upstreams.*.timeout`, then by `x-flexway-timeout`.",
              "not": {
                "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
              },
              "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
              "type": "string",
              "x-flexway-description": {
                "en": "Budget of the whole exchange, retries included; a streamed response is exempt from it. Default `30s`. Overridden by `upstreams.*.timeout`, then by `x-flexway-timeout`.",
                "fr": "Budget de l'échange entier, reprises comprises ; une réponse en flux en est exemptée. Défaut `30s`. Surchargé par `upstreams.*.timeout`, puis par `x-flexway-timeout`."
              },
              "x-flexway-reloadable": true,
              "x-flexway-since": "0.2.0"
            }
          },
          "type": "object",
          "x-flexway-description": {
            "en": "Budgets of one relayed exchange, in layers. There is deliberately no single global timeout.",
            "fr": "Budgets d'un échange relayé, par couches. Il n'y a volontairement pas de délai global unique."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.2.0"
        },
        "tls": {
          "additionalProperties": false,
          "description": "The gateway terminates TLS itself, on a listener of its own, and asks for a client certificate, verified against `client_ca_file` when presented. Read once at start; the files are read again when they rotate.",
          "properties": {
            "cert_file": {
              "description": "Path of the TLS listener's certificate (PEM). Required.",
              "type": "string",
              "x-flexway-description": {
                "en": "Path of the TLS listener's certificate (PEM). Required.",
                "fr": "Chemin du certificat de l'écouteur TLS (PEM). Obligatoire."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "0.7.0"
            },
            "client_ca_file": {
              "description": "Path of the authority (PEM) that verifies presented client certificates. Absent: no client certificate is verified.",
              "type": "string",
              "x-flexway-description": {
                "en": "Path of the authority (PEM) that verifies presented client certificates. Absent: no client certificate is verified.",
                "fr": "Chemin de l'autorité (PEM) qui vérifie les certificats clients présentés. Absent : aucun certificat client vérifié."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "0.7.0"
            },
            "key_file": {
              "description": "Path of the TLS listener's private key (PEM). Required.",
              "type": "string",
              "x-flexway-description": {
                "en": "Path of the TLS listener's private key (PEM). Required.",
                "fr": "Chemin de la clé privée de l'écouteur TLS (PEM). Obligatoire."
              },
              "x-flexway-reloadable": false,
              "x-flexway-since": "0.7.0"
            }
          },
          "required": [
            "cert_file",
            "key_file"
          ],
          "type": "object",
          "x-flexway-description": {
            "en": "The gateway terminates TLS itself, on a listener of its own, and asks for a client certificate, verified against `client_ca_file` when presented. Read once at start; the files are read again when they rotate.",
            "fr": "La passerelle termine TLS elle-même, sur un écouteur à part, et demande un certificat client, vérifié contre `client_ca_file` s'il est présenté. Lu une seule fois au démarrage ; les fichiers sont relus à leur rotation."
          },
          "x-flexway-reloadable": false,
          "x-flexway-since": "0.7.0"
        },
        "trusted_proxies": {
          "description": "Peers (CIDR, for instance `10.0.0.0/8`) whose `X-Forwarded-For` is believed - the edge; from anyone else the header is ignored. `local` names the pod's own addresses (a mesh proxy). None by default.",
          "items": {
            "type": "string"
          },
          "type": "array",
          "x-flexway-description": {
            "en": "Peers (CIDR, for instance `10.0.0.0/8`) whose `X-Forwarded-For` is believed - the edge; from anyone else the header is ignored. `local` names the pod's own addresses (a mesh proxy). None by default.",
            "fr": "Pairs (CIDR, par exemple `10.0.0.0/8`) dont `X-Forwarded-For` est cru - l'edge ; venant de tout autre, l'en-tête est ignoré. `local` désigne les adresses propres du pod (un proxy de maillage). Aucun par défaut."
          },
          "x-flexway-reloadable": true,
          "x-flexway-since": "0.4.0"
        }
      },
      "type": "object",
      "x-flexway-description": {
        "en": "How the gateway behaves toward its upstreams and during a shutdown, independently of any operation. Every key has a default: an empty `server:` section is valid.",
        "fr": "Comportement de la passerelle face à ses amonts et à l'arrêt, indépendamment de toute opération. Chaque clé a un défaut : une section `server:` vide est valide."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.2.0"
    },
    "upstreams": {
      "additionalProperties": {
        "additionalProperties": false,
        "properties": {
          "allow_private": {
            "description": "Webhook only: opens the private address ranges to the connection guard (and `http://`), refused by default. Default `false`.",
            "type": "boolean",
            "x-flexway-description": {
              "en": "Webhook only: opens the private address ranges to the connection guard (and `http://`), refused by default. Default `false`.",
              "fr": "Webhook seulement : ouvre les plages d'adresses privées à la garde de connexion (et `http://`), refusées par défaut. Défaut `false`."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "1.5.0"
          },
          "amqp1": {
            "additionalProperties": false,
            "description": "AMQP 1.0 only (`protocol: amqp`, `protocol_version: \"1.0\"`): what the broker does beyond the standard.",
            "properties": {
              "broker": {
                "default": "generic",
                "description": "AMQP 1.0 broker: `rabbitmq`, `artemis`, `solace`, `servicebus` or `generic` (default). It says how a stream reads a channel without taking the messages of other consumers; `servicebus` and `generic` publish and deliver by webhook only.",
                "enum": [
                  "rabbitmq",
                  "artemis",
                  "solace",
                  "servicebus",
                  "generic"
                ],
                "type": "string",
                "x-flexway-description": {
                  "en": "AMQP 1.0 broker: `rabbitmq`, `artemis`, `solace`, `servicebus` or `generic` (default). It says how a stream reads a channel without taking the messages of other consumers; `servicebus` and `generic` publish and deliver by webhook only.",
                  "fr": "Courtier AMQP 1.0 : `rabbitmq`, `artemis`, `solace`, `servicebus` ou `generic` (défaut). Il dit comment un flux lit un canal sans prendre les messages des autres consommateurs ; `servicebus` et `generic` publient et livrent par webhook seulement."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.6.0"
              }
            },
            "type": "object",
            "x-flexway-description": {
              "en": "AMQP 1.0 only (`protocol: amqp`, `protocol_version: \"1.0\"`): what the broker does beyond the standard.",
              "fr": "AMQP 1.0 seulement (`protocol: amqp`, `protocol_version: \"1.0\"`) : ce que fait le courtier au-delà du standard."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "1.6.0"
          },
          "brokers": {
            "description": "Brokers only (`kafka`, `amqp`, `mqtt`, `nats`), required: bootstrap addresses. Kafka: `host:port`; AMQP and MQTT: an `amqp://` or `amqps://`, `mqtt://` or `mqtts://` URL; NATS: `nats://` or `tls://`. Never credentials in the address.",
            "items": {
              "type": "string"
            },
            "type": "array",
            "x-flexway-description": {
              "en": "Brokers only (`kafka`, `amqp`, `mqtt`, `nats`), required: bootstrap addresses. Kafka: `host:port`; AMQP and MQTT: an `amqp://` or `amqps://`, `mqtt://` or `mqtts://` URL; NATS: `nats://` or `tls://`. Never credentials in the address.",
              "fr": "Courtiers seulement (`kafka`, `amqp`, `mqtt`, `nats`), obligatoire : adresses d'amorçage. Kafka : `hôte:port` ; AMQP et MQTT : URL `amqp://` ou `amqps://`, `mqtt://` ou `mqtts://` ; NATS : `nats://` ou `tls://`. Jamais d'identifiant dans l'adresse."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "1.5.0"
          },
          "circuit_breaker": {
            "additionalProperties": false,
            "description": "The upstream's circuit breaker, always on: it opens when too many calls fail, refuses at once while resting, then lets one trial call through. Every key has a default.",
            "properties": {
              "cooldown": {
                "default": "5s",
                "description": "How long the open breaker rests before the trial call; default `5s`.",
                "not": {
                  "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
                },
                "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
                "type": "string",
                "x-flexway-description": {
                  "en": "How long the open breaker rests before the trial call; default `5s`.",
                  "fr": "Repos du coupe-circuit ouvert avant l'appel d'essai ; défaut `5s`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.4.0"
              },
              "failure_ratio": {
                "default": 0.5,
                "description": "Share of failing calls that opens the breaker, in `(0, 1]`; default `0.5`.",
                "maximum": 1,
                "minimum": 0,
                "type": "number",
                "x-flexway-description": {
                  "en": "Share of failing calls that opens the breaker, in `(0, 1]`; default `0.5`.",
                  "fr": "Part d'appels en échec qui ouvre le coupe-circuit, dans `]0, 1]` ; défaut `0.5`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.4.0"
              },
              "min_requests": {
                "default": 20,
                "description": "Minimum number of calls in the window before the ratio is judged; default `20`.",
                "minimum": 1,
                "type": "integer",
                "x-flexway-description": {
                  "en": "Minimum number of calls in the window before the ratio is judged; default `20`.",
                  "fr": "Nombre minimal d'appels dans la fenêtre avant de juger le ratio ; défaut `20`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.4.0"
              },
              "window": {
                "default": "10s",
                "description": "Rolling window over which failures are counted; default `10s`.",
                "not": {
                  "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
                },
                "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
                "type": "string",
                "x-flexway-description": {
                  "en": "Rolling window over which failures are counted; default `10s`.",
                  "fr": "Fenêtre glissante sur laquelle les échecs sont comptés ; défaut `10s`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.4.0"
              }
            },
            "type": "object",
            "x-flexway-description": {
              "en": "The upstream's circuit breaker, always on: it opens when too many calls fail, refuses at once while resting, then lets one trial call through. Every key has a default.",
              "fr": "Coupe-circuit de l'amont, toujours actif : il s'ouvre quand trop d'appels échouent, refuse aussitôt pendant le repos, puis laisse passer un appel d'essai. Chaque clé a un défaut."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "0.4.0"
          },
          "max_in_flight": {
            "description": "Requests relayed to this upstream at once; past it, `503` at once (bulkhead). `0`: no cap. For a broker, bounds the publications waiting for an acknowledgement, `1024` by default.",
            "minimum": 0,
            "type": "integer",
            "x-flexway-description": {
              "en": "Requests relayed to this upstream at once; past it, `503` at once (bulkhead). `0`: no cap. For a broker, bounds the publications waiting for an acknowledgement, `1024` by default.",
              "fr": "Requêtes relayées à la fois vers cet amont ; au-delà, `503` aussitôt (cloisonnement). `0` : sans plafond. Pour un courtier, borne les publications en attente d'accusé, `1024` par défaut."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "0.4.0"
          },
          "nats": {
            "additionalProperties": false,
            "description": "NATS only: the gateway's identity and JetStream. One identity at most - `credentials`, `nkey_seed` or `token`, or `sasl` PLAIN; with none, an anonymous connection is admitted only with a client certificate or inside a declared mesh.",
            "properties": {
              "credentials": {
                "description": "NATS credentials file (JWT and nkey seed), by reference (`${VAR}` or `file:/path`).",
                "pattern": "^(\\$\\{[A-Za-z_][A-Za-z0-9_]*\\}|file:/\\S+)$",
                "type": "string",
                "x-flexway-description": {
                  "en": "NATS credentials file (JWT and nkey seed), by reference (`${VAR}` or `file:/path`).",
                  "fr": "Fichier d'identifiants NATS (JWT et graine nkey), par référence (`${VAR}` ou `file:/chemin`)."
                },
                "x-flexway-reference": true,
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.6.0"
              },
              "domain": {
                "description": "JetStream domain (a super-cluster, a leaf node), optional: one token, without dot, space, `*` nor `>`. Does nothing with `jetstream: false`, so refused.",
                "type": "string",
                "x-flexway-description": {
                  "en": "JetStream domain (a super-cluster, a leaf node), optional: one token, without dot, space, `*` nor `>`. Does nothing with `jetstream: false`, so refused.",
                  "fr": "Domaine JetStream (super-grappe, nœud feuille), facultatif : un seul jeton, sans point, espace, `*` ni `>`. Sans effet avec `jetstream: false`, donc refusé."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.6.0"
              },
              "jetstream": {
                "default": true,
                "description": "Publish and consume through JetStream (publications acknowledged by a stream); default `true`. `false`: NATS Core, read by server-sent events only, never published to.",
                "type": "boolean",
                "x-flexway-description": {
                  "en": "Publish and consume through JetStream (publications acknowledged by a stream); default `true`. `false`: NATS Core, read by server-sent events only, never published to.",
                  "fr": "Publier et consommer par JetStream (publication accusée par un flux) ; défaut `true`. `false` : NATS Core, lu en server-sent events seulement, jamais publié."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.6.0"
              },
              "nkey_seed": {
                "description": "An nkey seed alone, by reference (`${VAR}` or `file:/path`).",
                "pattern": "^(\\$\\{[A-Za-z_][A-Za-z0-9_]*\\}|file:/\\S+)$",
                "type": "string",
                "x-flexway-description": {
                  "en": "An nkey seed alone, by reference (`${VAR}` or `file:/path`).",
                  "fr": "Graine nkey seule, par référence (`${VAR}` ou `file:/chemin`)."
                },
                "x-flexway-reference": true,
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.6.0"
              },
              "token": {
                "description": "NATS token, by reference; it is sent as it is, so TLS is required (`tls` or a `tls://` broker).",
                "pattern": "^(\\$\\{[A-Za-z_][A-Za-z0-9_]*\\}|file:/\\S+)$",
                "type": "string",
                "x-flexway-description": {
                  "en": "NATS token, by reference; it is sent as it is, so TLS is required (`tls` or a `tls://` broker).",
                  "fr": "Jeton NATS, par référence ; il est envoyé tel quel, d'où TLS obligatoire (`tls` ou un courtier `tls://`)."
                },
                "x-flexway-reference": true,
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.6.0"
              }
            },
            "type": "object",
            "x-flexway-description": {
              "en": "NATS only: the gateway's identity and JetStream. One identity at most - `credentials`, `nkey_seed` or `token`, or `sasl` PLAIN; with none, an anonymous connection is admitted only with a client certificate or inside a declared mesh.",
              "fr": "NATS seulement : identité de la passerelle et JetStream. Une seule identité au plus - `credentials`, `nkey_seed` ou `token`, ou `sasl` PLAIN ; sans aucune, une connexion anonyme n'est admise qu'avec un certificat client ou dans un maillage déclaré."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "1.6.0"
          },
          "pool": {
            "additionalProperties": false,
            "description": "Connections kept to this upstream. Not for a broker or a webhook, which keep their own connections.",
            "properties": {
              "idle_timeout": {
                "default": "1m30s",
                "description": "How long an idle connection is kept before it is closed; default `90s`.",
                "not": {
                  "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
                },
                "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
                "type": "string",
                "x-flexway-description": {
                  "en": "How long an idle connection is kept before it is closed; default `90s`.",
                  "fr": "Durée de vie d'une connexion inactive avant sa fermeture ; défaut `90s`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.2.0"
              },
              "max_conns": {
                "description": "Connections open to the upstream at once; `0` (default): no cap. A cap turns a slowdown into queueing at the gateway instead of a connection storm.",
                "minimum": 0,
                "type": "integer",
                "x-flexway-description": {
                  "en": "Connections open to the upstream at once; `0` (default): no cap. A cap turns a slowdown into queueing at the gateway instead of a connection storm.",
                  "fr": "Connexions ouvertes à la fois vers l'amont ; `0` (défaut) : sans plafond. Un plafond transforme un ralentissement en file à la passerelle plutôt qu'en tempête de connexions."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.2.0"
              },
              "max_idle": {
                "default": 100,
                "description": "Idle connections kept for reuse; default `100`. `0` or absent: the default - disabling reuse is not offered.",
                "type": "integer",
                "x-flexway-description": {
                  "en": "Idle connections kept for reuse; default `100`. `0` or absent: the default - disabling reuse is not offered.",
                  "fr": "Connexions inactives gardées pour réutilisation ; défaut `100`. `0` ou absent : le défaut - désactiver la réutilisation n'est pas offert."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.2.0"
              }
            },
            "type": "object",
            "x-flexway-description": {
              "en": "Connections kept to this upstream. Not for a broker or a webhook, which keep their own connections.",
              "fr": "Connexions gardées vers cet amont. Sans objet pour un courtier ou un webhook, qui gardent leurs propres connexions."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "0.2.0"
          },
          "protocol": {
            "default": "http",
            "description": "The upstream's protocol: `http` (default, `https://` included), `grpc` (HTTP/2, h2c in clear inside a mesh), `mcp` (a federated MCP server), `a2a` (an A2A agent, `token_exchange` required), `kafka`, `amqp`, `mqtt`, `nats` (brokers) or `webhook` (a delivery target).",
            "enum": [
              "http",
              "grpc",
              "mcp",
              "a2a",
              "kafka",
              "amqp",
              "mqtt",
              "nats",
              "webhook"
            ],
            "type": "string",
            "x-flexway-description": {
              "en": "The upstream's protocol: `http` (default, `https://` included), `grpc` (HTTP/2, h2c in clear inside a mesh), `mcp` (a federated MCP server), `a2a` (an A2A agent, `token_exchange` required), `kafka`, `amqp`, `mqtt`, `nats` (brokers) or `webhook` (a delivery target).",
              "fr": "Protocole de l'amont : `http` (défaut, `https://` compris), `grpc` (HTTP/2, h2c en clair dans un maillage), `mcp` (serveur MCP fédéré), `a2a` (agent A2A, `token_exchange` obligatoire), `kafka`, `amqp`, `mqtt`, `nats` (courtiers) ou `webhook` (cible de livraison)."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "0.1.0"
          },
          "protocol_version": {
            "description": "Protocol version, AMQP and MQTT only: MQTT `5` (default) or `3.1.1`; AMQP `0-9-1` (default) or `1.0`. Kafka and NATS negotiate their version: the key is refused.",
            "enum": [
              "5",
              "3.1.1",
              "0-9-1",
              "1.0"
            ],
            "type": "string",
            "x-flexway-description": {
              "en": "Protocol version, AMQP and MQTT only: MQTT `5` (default) or `3.1.1`; AMQP `0-9-1` (default) or `1.0`. Kafka and NATS negotiate their version: the key is refused.",
              "fr": "Version du protocole, AMQP et MQTT seulement : MQTT `5` (défaut) ou `3.1.1` ; AMQP `0-9-1` (défaut) ou `1.0`. Kafka et NATS négocient leur version : clé refusée."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "1.5.0"
          },
          "retries": {
            "additionalProperties": false,
            "description": "Webhook only: bounded retries of a delivery.",
            "properties": {
              "max": {
                "default": 8,
                "description": "Retries of a delivery at most, from `0` to `20`; default `8`.",
                "maximum": 20,
                "minimum": 0,
                "type": "integer",
                "x-flexway-description": {
                  "en": "Retries of a delivery at most, from `0` to `20`; default `8`.",
                  "fr": "Réessais au plus d'une livraison, de `0` à `20` ; défaut `8`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.5.0"
              },
              "max_delay": {
                "default": "10m",
                "description": "Longest delay between two attempts; default `10m`.",
                "not": {
                  "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
                },
                "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
                "type": "string",
                "x-flexway-description": {
                  "en": "Longest delay between two attempts; default `10m`.",
                  "fr": "Délai au plus entre deux tentatives ; défaut `10m`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.5.0"
              }
            },
            "type": "object",
            "x-flexway-description": {
              "en": "Webhook only: bounded retries of a delivery.",
              "fr": "Webhook seulement : réessais bornés d'une livraison."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "1.5.0"
          },
          "sasl": {
            "additionalProperties": false,
            "description": "Brokers only: how the gateway authenticates to the broker - its own identity, never a caller's.",
            "properties": {
              "mechanism": {
                "description": "SASL mechanism: Kafka `PLAIN`, `SCRAM-SHA-256` or `SCRAM-SHA-512`; AMQP 0-9-1, MQTT and NATS `PLAIN`; AMQP 1.0 `PLAIN`, `ANONYMOUS` (with a client certificate or inside a mesh) or `EXTERNAL` (the client certificate as identity). `PLAIN` over TLS only.",
                "enum": [
                  "PLAIN",
                  "SCRAM-SHA-256",
                  "SCRAM-SHA-512",
                  "ANONYMOUS",
                  "EXTERNAL"
                ],
                "type": "string",
                "x-flexway-description": {
                  "en": "SASL mechanism: Kafka `PLAIN`, `SCRAM-SHA-256` or `SCRAM-SHA-512`; AMQP 0-9-1, MQTT and NATS `PLAIN`; AMQP 1.0 `PLAIN`, `ANONYMOUS` (with a client certificate or inside a mesh) or `EXTERNAL` (the client certificate as identity). `PLAIN` over TLS only.",
                  "fr": "Mécanisme SASL : Kafka `PLAIN`, `SCRAM-SHA-256` ou `SCRAM-SHA-512` ; AMQP 0-9-1, MQTT et NATS `PLAIN` ; AMQP 1.0 `PLAIN`, `ANONYMOUS` (avec certificat client ou dans un maillage) ou `EXTERNAL` (le certificat client comme identité). `PLAIN` seulement sur TLS."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.5.0"
              },
              "password": {
                "description": "Password, by reference (`${VAR}` or `file:/path`). Absent with `ANONYMOUS` and `EXTERNAL`.",
                "pattern": "^(\\$\\{[A-Za-z_][A-Za-z0-9_]*\\}|file:/\\S+)$",
                "type": "string",
                "x-flexway-description": {
                  "en": "Password, by reference (`${VAR}` or `file:/path`). Absent with `ANONYMOUS` and `EXTERNAL`.",
                  "fr": "Mot de passe, par référence (`${VAR}` ou `file:/chemin`). Absent avec `ANONYMOUS` et `EXTERNAL`."
                },
                "x-flexway-reference": true,
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.5.0"
              },
              "username": {
                "description": "The gateway's user name at the broker. Absent with `ANONYMOUS` and `EXTERNAL`.",
                "type": "string",
                "x-flexway-description": {
                  "en": "The gateway's user name at the broker. Absent with `ANONYMOUS` and `EXTERNAL`.",
                  "fr": "Nom d'utilisateur de la passerelle auprès du courtier. Absent avec `ANONYMOUS` et `EXTERNAL`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "1.5.0"
              }
            },
            "required": [
              "mechanism"
            ],
            "type": "object",
            "x-flexway-description": {
              "en": "Brokers only: how the gateway authenticates to the broker - its own identity, never a caller's.",
              "fr": "Courtiers seulement : comment la passerelle s'authentifie auprès du courtier - sa propre identité, jamais celle d'un appelant."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "1.5.0"
          },
          "secrets": {
            "description": "Webhook only: signing secrets (Standard Webhooks), by reference - one, or two during a rotation.",
            "items": {
              "pattern": "^(\\$\\{[A-Za-z_][A-Za-z0-9_]*\\}|file:/\\S+)$",
              "type": "string",
              "x-flexway-reference": true
            },
            "maxItems": 2,
            "type": "array",
            "x-flexway-description": {
              "en": "Webhook only: signing secrets (Standard Webhooks), by reference - one, or two during a rotation.",
              "fr": "Webhook seulement : secrets de signature (Standard Webhooks), par référence - un seul, ou deux pendant une rotation."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "1.5.0"
          },
          "timeout": {
            "description": "Total budget of an exchange with this upstream (`3s`), never a count of nanoseconds. Overrides `server.timeouts.total`, overridden in turn by `x-flexway-timeout`. For a broker: a publication's budget, acknowledgement included.",
            "not": {
              "pattern": "^(0+(\\.0+)?(ns|us|µs|ms|s|m|h))+$"
            },
            "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$",
            "type": "string",
            "x-flexway-description": {
              "en": "Total budget of an exchange with this upstream (`3s`), never a count of nanoseconds. Overrides `server.timeouts.total`, overridden in turn by `x-flexway-timeout`. For a broker: a publication's budget, acknowledgement included.",
              "fr": "Budget total d'un échange avec cet amont (`3s`), jamais un compte de nanosecondes. Surcharge `server.timeouts.total`, surchargé à son tour par `x-flexway-timeout`. Pour un courtier : budget d'une publication, accusé compris."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "0.2.0"
          },
          "tls": {
            "additionalProperties": false,
            "description": "Client TLS toward the upstream outside a mesh: authority, client certificate, expected name. Only with an `https://` URL (or a TLS broker); inside a mesh the sidecar does mTLS and the URL stays `http://`. No client certificate toward a webhook.",
            "properties": {
              "ca_file": {
                "description": "Path of the authority (PEM) that verifies the upstream's certificate. Absent: the system authorities.",
                "type": "string",
                "x-flexway-description": {
                  "en": "Path of the authority (PEM) that verifies the upstream's certificate. Absent: the system authorities.",
                  "fr": "Chemin de l'autorité (PEM) qui vérifie le certificat de l'amont. Absent : les autorités du système."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.3.0"
              },
              "cert_file": {
                "description": "Path of the client certificate (PEM) presented to the upstream; goes with `key_file`.",
                "type": "string",
                "x-flexway-description": {
                  "en": "Path of the client certificate (PEM) presented to the upstream; goes with `key_file`.",
                  "fr": "Chemin du certificat client (PEM) présenté à l'amont ; va avec `key_file`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.3.0"
              },
              "key_file": {
                "description": "Path of the client certificate's private key (PEM); goes with `cert_file`.",
                "type": "string",
                "x-flexway-description": {
                  "en": "Path of the client certificate's private key (PEM); goes with `cert_file`.",
                  "fr": "Chemin de la clé privée du certificat client (PEM) ; va avec `cert_file`."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.3.0"
              },
              "server_name": {
                "description": "Name expected in the upstream's certificate (SNI), when it differs from the URL's host.",
                "type": "string",
                "x-flexway-description": {
                  "en": "Name expected in the upstream's certificate (SNI), when it differs from the URL's host.",
                  "fr": "Nom attendu dans le certificat de l'amont (SNI), quand il diffère de l'hôte de l'URL."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.3.0"
              }
            },
            "type": "object",
            "x-flexway-description": {
              "en": "Client TLS toward the upstream outside a mesh: authority, client certificate, expected name. Only with an `https://` URL (or a TLS broker); inside a mesh the sidecar does mTLS and the URL stays `http://`. No client certificate toward a webhook.",
              "fr": "TLS client vers l'amont hors maillage : autorité, certificat client, nom attendu. Seulement avec une URL `https://` (ou un courtier TLS) ; dans un maillage, le sidecar fait le mTLS et l'URL reste `http://`. Pas de certificat client vers un webhook."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "0.3.0"
          },
          "token_exchange": {
            "additionalProperties": false,
            "description": "This upstream receives a token issued for it on the caller's behalf (RFC 8693), on every call, REST and MCP alike, never the caller's own and with no fallback. Requires a `client` at the caller's issuer. Refused for a broker or a webhook.",
            "properties": {
              "audience": {
                "description": "Audience the upstream expects a token to be issued for (`orders-api`). Required.",
                "type": "string",
                "x-flexway-description": {
                  "en": "Audience the upstream expects a token to be issued for (`orders-api`). Required.",
                  "fr": "Audience pour laquelle l'amont attend un jeton (`orders-api`). Obligatoire."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.7.0"
              },
              "scope": {
                "description": "Scopes that narrow the exchanged token; empty: left to the provider.",
                "items": {
                  "type": "string"
                },
                "type": "array",
                "x-flexway-description": {
                  "en": "Scopes that narrow the exchanged token; empty: left to the provider.",
                  "fr": "Portées qui restreignent le jeton échangé ; vide : laissé au fournisseur."
                },
                "x-flexway-reloadable": true,
                "x-flexway-since": "0.7.0"
              }
            },
            "required": [
              "audience"
            ],
            "type": "object",
            "x-flexway-description": {
              "en": "This upstream receives a token issued for it on the caller's behalf (RFC 8693), on every call, REST and MCP alike, never the caller's own and with no fallback. Requires a `client` at the caller's issuer. Refused for a broker or a webhook.",
              "fr": "Cet amont reçoit un jeton émis pour lui au nom de l'appelant (RFC 8693), à chaque appel, REST et MCP, jamais celui de l'appelant ni de repli. Exige un `client` chez l'émetteur de l'appelant. Refusé pour un courtier ou un webhook."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "0.7.0"
          },
          "url": {
            "description": "The upstream's address: an absolute http(s) URL (`http://orders.internal:8080`), required except for a broker, reached through `brokers`. Webhook: an `https://` URL named by a host, never an IP address, without credentials.",
            "type": "string",
            "x-flexway-description": {
              "en": "The upstream's address: an absolute http(s) URL (`http://orders.internal:8080`), required except for a broker, reached through `brokers`. Webhook: an `https://` URL named by a host, never an IP address, without credentials.",
              "fr": "Adresse de l'amont : URL http(s) absolue (`http://orders.internal:8080`), obligatoire sauf pour un courtier, qui se joint par `brokers`. Webhook : URL `https://` nommée par un hôte, jamais une adresse IP, sans identifiant."
            },
            "x-flexway-reloadable": true,
            "x-flexway-since": "0.1.0"
          }
        },
        "type": "object"
      },
      "description": "The upstreams, by name: where declared operations are relayed to, and the brokers and webhook targets of the asynchronous plane. At least one; the name `ai` is reserved for the inference surface.",
      "type": "object",
      "x-flexway-description": {
        "en": "The upstreams, by name: where declared operations are relayed to, and the brokers and webhook targets of the asynchronous plane. At least one; the name `ai` is reserved for the inference surface.",
        "fr": "Les amonts, par nom : où les opérations déclarées sont relayées, et les courtiers et cibles webhook du plan asynchrone. Au moins un ; le nom `ai` est réservé à la surface d'inférence."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.1.0"
    },
    "version": {
      "description": "Version of the file's schema: `1`, the only value accepted. Required.",
      "enum": [
        1
      ],
      "type": "integer",
      "x-flexway-description": {
        "en": "Version of the file's schema: `1`, the only value accepted. Required.",
        "fr": "Version du schéma du fichier : `1`, seule valeur admise. Obligatoire."
      },
      "x-flexway-reloadable": true,
      "x-flexway-since": "0.1.0"
    }
  },
  "required": [
    "version"
  ],
  "title": "flexway.yaml",
  "type": "object",
  "x-flexway-description": {
    "en": "The gateway's configuration file: it says how things are served, never what. It lists no operation - it references the contracts and describes upstreams, hosts, identities and policies. Decoding is strict: an unknown key is refused, and every problem is reported at once.",
    "fr": "Le fichier de configuration de la passerelle : il dit comment servir, jamais quoi. Il ne liste aucune opération - il référence les contrats et décrit les amonts, hôtes, identités et politiques. Décodage strict : une clé inconnue est refusée, et tous les problèmes sont rapportés d'un coup."
  }
}
